POJ 2553 The Bottom of a Graph 强联通分量
2012-08-21 11:01 javaspring 阅读(227) 评论(0) 编辑 收藏 举报来源:http://poj.org/problem?id=2553
题意:题目新给了一个定义,在一个图中,若从点v能够到达点w,且从w能够到达点v,则称v为sink。让输出一个图中sink的序号,按升序输出。
思路:首先根据定义,易知,因为是有向图,所以一个孤立的强联通分量里面的点都是sink,这点很容易理解,因为强联通分量里面的点都是互达的。而且该强联通分量是孤立的,也就是说,该强联通分量缩点后的出度为0。即缩点后该点到不了其他点,满足sink的定义。也就是说,该题就是求缩点后哪些点的出度为0,即为答案。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <vector> using namespace std; #define CLR(arr,val) memset(arr,val,sizeof(arr)) const int N = 5010; int low[N],dfn[N],numnode,numedge,head[N],numpath; int timeorder,ss[N],numss,vis[N],numQ[N],numcnt; int outdegree[N]; vector<int> vv[N]; struct edge{ int x,y,next; }ee[N * N]; void add_edge(int lp,int rp){ ee[numedge].x = lp; ee[numedge].y = rp; ee[numedge].next = head[lp]; head[lp] = numedge++; } int min(int a,int b){ return a < b ? a : b; } void targin(int x){ vis[x] = 1; timeorder++; numss++; dfn[x] = low[x] = timeorder; ss[numss] = x; for(int i = head[x]; i != -1; i = ee[i].next){ int rp = ee[i].y; if(!vis[rp]){ targin(rp); low[x] = min(low[x],low[rp]); } else if(vis[rp] == 1){ low[x] = min(low[x],dfn[rp]); } } if(low[x] == dfn[x]){ numcnt++; while(1){ int tt = ss[numss--]; vis[tt] = 2; numQ[tt] = numcnt; vv[numcnt].push_back(tt); if(tt == x) break; } } } void init(){ CLR(low,0); CLR(dfn,0); CLR(head,-1); CLR(ss,0); CLR(vis,0); CLR(numQ,0); CLR(outdegree,0); CLR(vv,0); timeorder = 0; numss = 0; numedge = 0; numcnt = 0; } int main(){ //freopen("1.txt","r",stdin); while(scanf("%d",&numnode) && numnode){ scanf("%d",&numpath); init(); int lp,rp; for(int i = 0; i < numpath; ++i){ scanf("%d%d",&lp,&rp); add_edge(lp,rp); } for(int i = 1; i <= numnode; ++i){ if(!dfn[i]) targin(i); } // printf("numcnt = %d\n",numcnt); for(int i = 0 ;i < numedge; ++i){ int leftp = numQ[ee[i].x]; int rightp = numQ[ee[i].y]; if(leftp != rightp){ outdegree[leftp]++; } } int ans[N], K = 0; for(int i = 1; i <= numcnt; ++i){ if(!outdegree[i]){ for(int j = 0;j < vv[i].size(); ++j){ ans[K++] = vv[i][j]; } } } sort(ans,ans+K); for(int i = 0; i < K-1; ++i) printf("%d ",ans[i]); printf("%d\n",ans[K-1]); } return 0; }