【个人专题一】强连通——Poj_2186
来源:互联网 发布:vue.js 2.0 api文档 编辑:程序博客网 时间:2024/04/30 02:55
思路1代码:#include<stdio.h>#include<vector>//#include<memory.h>using namespace std;//存储变量int x,y;vector<int> f[10000];//存储正向图vector<int> n[10000];//存储反向图bool sign[10000];//辅助变量int i,g,h,sum,r;void init(){//初始化memset(sign,0,sizeof(sign));sum=0;//清空相连表for(i=0;i<x;i++){f[i].clear();n[i].clear();} //存储相连表for(i=0;i<y;i++){scanf("%d%d",&g,&h);f[g-1].push_back(h-1);n[h-1].push_back(g-1);}r=0;}void search(int k,vector<int> l[10000]){vector<int>::iterator t;sign[k]=true;sum++;for(t=l[k].begin();t!=l[k].end();t++){if(!sign[*t])search(*t,l);}}int doit(){//在反向图里搜索源_强连通子图(即正向图的出度为0的强连通子图)for(i=0;i<x;i++){if(!sign[i]){r=i;search(r,n);}}//如果以r作为起点在反向图中深搜能遍历全图,则r就是受全部人欢迎的牛,否则不存在受全部人欢迎的牛,返回0sum=0;memset(sign,0,sizeof(sign));search(r,n);if(sum<x) return 0;//如果存在r,则与r在同一个强连通子图的牛都是受全部人欢迎的牛,计算其数目(因为已知r在反向图中能找到所有,//即正向图中都能找到r,则正向图中以r为根节点进行深搜,能碰到的点都是和r在同一个强连通子图中sum=0;memset(sign,0,sizeof(sign));search(r,f);return sum;}int main(){while(scanf("%d%d",&x,&y)!=EOF){init();printf("%d\n",doit());}return 0;}思路2代码:#include<iostream>using namespace std;#define DOTMAX 10001#define EDGEMAX 50001struct node{ int t; node *next;}dotset[EDGEMAX*3];//直接申请好全部空间,然后哪个空间放哪个节点临时生成即可int count=0;//每一个case后,count置为0node *Newnode()//调用上面申请好的全部空间里的一个节点作为存储地点{ node *p; p=&dotset[count]; count++; return p;}void Addnode(node hash[],int a,int b)//在相连表上插入一个节点{ node *p=&hash[a]; node *q=Newnode(); q->t=b; q->next=p->next; p->next=q;}node hash[DOTMAX];node nhash[DOTMAX];node New[DOTMAX];int gcc;int order[DOTMAX];int num;int id[DOTMAX];int visit[DOTMAX];int gccnum[DOTMAX];void init(node hash[],int n)//初始化相连表{ count=0; int i; for(i=1;i<=n;i++) { hash[i].t=-1; hash[i].next=NULL; }}int n,m;void dfs(int u)//正向图中深搜{ visit[u]=1; node *p; int v; for(p=hash[u].next;p!=NULL;p=p->next) { v=p->t; if(!visit[v]) { dfs(v); } } num++; order[num]=u;//用于反向搜索的顺序,可避免排序从而提高效率}void ndfs(int u)//反向图中搜索{ visit[u]=1; id[u]=gcc; node *p; int v; for(p=nhash[u].next;p!=NULL;p=p->next) { v=p->t; if(!visit[v]) { ndfs(v); } }}int main(){ int a,b,i; while(scanf("%d%d",&n,&m)!=EOF) {//初始化三个相连表 init(hash,n); init(nhash,n); init(New,n); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); Addnode(hash,a,b); Addnode(nhash,b,a); } memset(visit,0,sizeof(visit)); num=0;//正向深搜,找到根节点 for(i=1;i<=n;i++) { if(!visit[i]) dfs(i); } memset(visit,0,sizeof(visit)); gcc=0;//反向深搜 for(i=num;i>=1;i--) { if(!visit[order[i]]) { gcc++; ndfs(order[i]); } } for(i=1;i<=n;i++) { node *p; for(p=hash[i].next;p!=NULL;p=p->next) { if(id[i]!=id[p->t])//如果不是属于同一个强连通 { Addnode(New,id[i],id[p->t]);//构建新图相连表 } } } int cnt=0; memset(gccnum,0,sizeof(gccnum)); for(i=1;i<=n;i++) gccnum[id[i]]++;//各连通子图中的顶点个数 int mark=0; for(i=1;i<=gcc;i++)//搜索gcc个子图(视为顶点) { if(New[i].next==NULL)//出度为0 { cnt++; mark=i; } } if(cnt==1)//如果出度为0的只有一个,该连通子图的个数即所求个数 printf("%d\n",gccnum[mark]); else//无结果 printf("%d\n",0); }return 0;} 自己照思路2敲了一遍。。(344Ms)#include<stdio.h>#include<string.h>struct Node{int sub;Node *next;}hash[10001],nhash[10001],newhash[10001];bool IsVisit[10001];int N,M,order[10001],sum,setNum[10001],num[10001],setnum;//sum代表已经访问结束的顶点个数void init(int n)//初始化{int i;for(i=1;i<=n;i++)hash[i].next=nhash[i].next=newhash[i].next=NULL;memset(IsVisit,false,sizeof(IsVisit));memset(num,0,sizeof(num));sum=0;setnum=0;//强连通子图的标记}void AddNode(struct Node thash[],int tstt,int tend)//添加节点{struct Node *p=new struct Node;p->sub=tend;p->next=thash[tstt].next;thash[tstt].next=p;}void dfs(int x){IsVisit[x]=true;struct Node *p;for(p=hash[x].next;p!=NULL;p=p->next){if(!IsVisit[p->sub])dfs(p->sub);}order[++sum]=x;}void ndfs(int x){IsVisit[x]=true;setNum[x]=setnum;num[setnum]++;Node *p;for(p=nhash[x].next;p!=NULL;p=p->next){if(!IsVisit[p->sub])ndfs(p->sub);}}int main(){while(scanf("%d%d",&N,&M)!=EOF){init(N);int i,stt,end;for(i=1;i<=M;i++){scanf("%d%d",&stt,&end);AddNode(hash,stt,end);AddNode(nhash,end,stt);}for(i=1;i<=N;i++){if(!IsVisit[i]){dfs(i);}}memset(IsVisit,false,sizeof(IsVisit));for(i=N;i>0;i--){if(!IsVisit[order[i]]){setnum++;ndfs(order[i]);}}for(i=1;i<=N;i++){Node *p;for(p=hash[i].next;p!=NULL;p=p->next)//将强连通子图缩为一点,构建新图{if(setNum[i]!=setNum[p->sub])AddNode(newhash,setNum[i],setNum[p->sub]);}}int hole=0,k;for(i=1;i<=setnum;i++){if(newhash[i].next==NULL){hole++;k=i;}}if(hole==1) printf("%d\n",num[k]);else printf("0\n");}return 0;}
题目大意:在一群牛中,寻找受所有牛欢迎的牛的数量
思路1:
1、在反向图中深搜,找到“根节点”(最后结束的是“根节点”),然后在反向图中深搜“根节点”,如果能遍历全部顶点,则该点并是反向图中的根节点,也就是受所有牛欢迎的牛,转到2。否则输出0,结束。
2、 和该根节点的牛在同一强连通子图的牛也是受全部牛欢迎的牛。这里只要在正向图中深搜根节点,记录搜索到的数目,就是我们要的输出。
思路2:
1、在正向图中深搜,形成森林,记录各个节点的结束时间。
2、按时间从大到小在反向图中深搜,深搜未中断前,给每个被搜顶点记录相同且唯一的数字,代表属于同一个强连通子图(以上为Kosaraju算法)
3、利用强连通子图构建新图(此时必定无环,有环的已经属于同一个强连通子图而缩为新图的一个顶点
4、如果新图中出度为0的节点有多个,则返回0。否则返回出度为0的那个强连通子图中顶点的个数。
(思路2的代码来自http://www.cppblog.com/abilitytao/archive/2009/09/26/97302.html,不过我加了注释,需要吸收的是相连表用vector建立十分耗时,此外思路2的找强连通子图的做法在深搜完后不用排序即可立即进行反向搜索(可能已经很通用,只是我刚学,自己的思路是要排序,呵呵)
- 【个人专题一】强连通——Poj_2186
- 【个人专题一】强连通——Poj_1236
- 【个人专题一】强连通——Poj_2553
- 【个人专题一】强连通+拓扑排序——Poj_2762
- 【个人专题一】强连通——Hoj_1269
- 【个人专题一】强连通——Hoj_3639(RE)
- POJ_2186 Popular Cows(强连通分量)
- poj_2186 Popular Cows(强连通分量)
- 【图论】强连通专题总结
- tarjan求强连通分量专题
- 强连通算法--Tarjan个人理解+详解
- tarjan强连通分量算法个人理解
- 【省选】算法总结——强连通
- 强连通分量——kosaraju算法
- 菜鸟系列——强连通分量
- 强连通分量——Kosaraju算法
- 强连通分量——tarjan
- 强连通分量入门——UVA
- Eclipse添加Android系统库
- TBuf 转 TBuf8
- 也谈QT线程编程
- Java RMI的使用
- 详解Oracle数据货场中三种优化
- 【个人专题一】强连通——Poj_2186
- DataStage开发步骤 及进行数据整合
- buffer_pool & cache 区别与联系!!!
- 让你的Lable拥有系统自带 表情!
- 设计模式C++实现(15)——观察者模式
- 什么是“引用”?申明和使用“引用”要注意哪些问题?
- Axis2 - Timeout waiting for connection 问题解决方法
- 机房收费系统
- 8086汇编语言学习笔记