pku 2553

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=2553  极大强连通分量

题目大意:给出一个新定义sink,对于一个顶点v,他能到图G的一些点{W},并且{w}也能到达点v。也就是说v和{w}所构成的子图中任意两个点可以相互到达,呵呵。。这就符合的有向图的强连通分量的概念了,那么题意就是要求出所有的sink点。即求出内有出度的强连通分量。。。。。那么,现在的难点就是求,强连通分量了,那么我用的就是Kosarju算法 ,其他两种貌似比较高效的算法,我一直没搞懂,若有大牛路过,请多多指教。。。。呵呵

#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define MAX 20000 #define MAX2 5001 struct Graph { int id; int next; }; struct Edge { int s,e; }; Graph GA[MAX],GT[MAX]; Edge E[MAX]; int visit[MAX2]; int out[MAX2]; int belong[MAX2]; int order[MAX2]; int num[MAX2]; int number[MAX2]; int n,m,G_end,cnt; void init(int s,int e) { int p; p=s; while(GA[p].next) p=GA[p].next; GA[G_end].id=e; GA[p].next=G_end; p=e; while(GT[p].next) p=GT[p].next; GT[G_end].id=s; GT[p].next=G_end; G_end++; } void DFSA(int x) { int p,q; visit[x]=1; p=GA[x].next; while(p) { q=GA[p].id; if(!visit[q]) DFSA(q); p=GA[p].next; } order[cnt++]=x; } void DFST(int x) { int p,q; visit[x]=1; p=GT[x].next; while(p) { q=GT[p].id; if(!visit[q]) DFST(q); p=GT[p].next; } belong[x]=cnt; num[cnt]++; } int main() { while(scanf("%d",&n)&&n) { scanf("%d",&m); G_end=n+1; memset(GA,0,sizeof(GA)); memset(GT,0,sizeof(GT)); int s,e; for(int i=0;i<m;i++) { scanf("%d%d",&s,&e); E[i].s=s-1; E[i].e=e-1; init(s-1,e-1); } cnt=0; memset(visit,0,sizeof(visit)); for(int i=0;i<n;i++) if(!visit[i]) DFSA(i); cnt=0; memset(visit,0,sizeof(visit)); for(int i=n-1;i>=0;i--) { if(!visit[order[i]]) { DFST(order[i]); cnt++; } } memset(out,0,sizeof(out)); for(int i=0;i<m;i++) { s=belong[E[i].s]; e=belong[E[i].e]; if(s!=e) out[s]++; } int scnt=cnt; int pos=0,t=0; for(int i=0;i<scnt;i++) { if(out[i]==0) { for(int j=0;j<n;j++) if(belong[j]==i) { number[t]=j; t++; } pos=1; } } if(pos==0) printf("/n"); else { sort(number,number+t); printf("%d",number[0]+1); for(int i=1;i<t;i++) printf(" %d",number[i]+1); printf("/n"); } } return 0; }   

你可能感兴趣的:(pku 2553)