hdu1269--求强连通分量个数--tarjan--图的静态邻接表

来源:互联网 发布:中国人口流动数据 编辑:程序博客网 时间:2024/04/29 15:03
#include<stdio.h>#include<string.h>#include<stack>using namespace std;stack<int>s;int ret;struct node{int v,next;} e[100010];int ins[10010],fang[10010],head[10010],low[10010];int n,m,yong;void tarjan(int k){int j,u;fang[k]=low[k]=yong++;ins[k]=1;s.push(k);//强连通为什么要用栈?栈中其往上的都是可能和他是同一连通分量的,不可以访问非栈上节点是他们不可能在同一连通分量上(访问过而不在栈上,还可能是同一连通分量么),若访问 访问过而不在栈上 的节点(不是同一连通分量,他们早已出栈,说明他们的根还是比较高的,对他没有更新)for(j=head[k];j;j=e[j].next){u=e[j].v;if(fang[u]==0){tarjan(u);if(low[u]<low[k])low[k]=low[u];}else if(ins[u]&&fang[u]<low[k])//u可能在上一路上已被访问过,或者u就是k的祖先,他们一定是同一连通分量;与双连通不同的是:他要求的是自己不越过自己,所以,即使他有回边,早晚更新都是一样;双连通担心的是他提前更新,导致他的孩子也提前更新,从而fang[本节点]>low[孩子]=low[本节点]=low[本节点的父节点]low[k]=fang[u];}if(low[k]==fang[k])//其能探到的最低的不越过他自己,说明其以下是一个连通分量{ret++;do{j=s.top();s.pop();ins[j]=0;}while(j!=k);}}int main(){int i,a,b;while(1){ret=0;yong=1;scanf("%d%d",&n,&m);if(n==0&&m==0)break;memset(head,0,sizeof(head));for(i=1;i<=m;i++){scanf("%d%d",&a,&b);e[yong].v=b;e[yong].next=head[a];head[a]=yong;yong++;}yong=1;memset(ins,0,sizeof(ins));memset(fang,0,sizeof(fang));for(i=1;i<=n;i++)if(fang[i]==0)tarjan(i);if(ret==1)printf("Yes\n");else printf("No\n");}return 0;}