poj 2553 The Bottom of a Graph(强连通、缩点、出入度)

题意:给出一个有向图G,寻找所有的sink点。“sink”的定义为:{v∈V|∀w∈V:(v→w)⇒(w→v)},对于一个点v,所有能到达的所有节点w,都能够回到v,这样的点v称为sink。

分析:由(v→w),(w→v)可知,节点v,w构成强连通,很自然的想到要缩点。缩点之后,DAG上的每一条边,都是单向的(v->w),无回路(w->v)。

错误:对于v可达的点w,不仅是直接连边——从一个强连通子集A到另一个强连通子集B,意味着,子集A中的点都不可能是sink点。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<stack>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int MAXN=5555;
  8 
  9 struct Edge{
 10     int v,next;
 11     Edge(){}
 12     Edge(int _v,int _next):v(_v),next(_next){}
 13 }edge[MAXN*MAXN];
 14 
 15 int head[MAXN],tol;
 16 int pre[MAXN],low[MAXN],sccno[MAXN],dfs_clock,scc_cnt;
 17 int vis[MAXN];
 18 
 19 stack<int>stk;
 20 
 21 void init(int n)
 22 {
 23     tol=0;
 24     memset(head,-1,sizeof(head));
 25 }
 26 
 27 void add(int u,int v)
 28 {
 29     edge[tol]=Edge(v,head[u]);
 30     head[u]=tol++;
 31 }
 32 
 33 void dfs(int u)
 34 {
 35     int v;
 36     pre[u]=low[u]=++dfs_clock;
 37     stk.push(u);
 38     for(int i=head[u];i!=-1;i=edge[i].next)
 39     {
 40         v=edge[i].v;
 41         if(!pre[v]){
 42             dfs(v);
 43             low[u]=min(low[u],low[v]);
 44         }else if(!sccno[v])
 45             low[u]=min(low[u],pre[v]);
 46     }
 47     if(pre[u]==low[u]){
 48         scc_cnt++;
 49         do{
 50             v=stk.top();
 51             stk.pop();
 52             sccno[v]=scc_cnt;
 53         }while(u!=v);
 54     }
 55 }
 56 
 57 void find_scc(int n)
 58 {
 59     dfs_clock=scc_cnt=0;
 60     memset(pre,0,sizeof(pre));
 61     memset(low,0,sizeof(low));
 62     memset(sccno,0,sizeof(sccno));
 63 
 64     for(int i=1;i<=n;i++)
 65         if(!pre[i])
 66             dfs(i);
 67 }
 68 
 69 void check(int n)
 70 {
 71     memset(vis,0,sizeof(vis));
 72     for(int i=1;i<=n;i++)
 73     {
 74         for(int j=head[i];j!=-1;j=edge[j].next)
 75         {
 76             int v=edge[j].v;
 77             if(sccno[i]!=sccno[v])
 78                 vis[sccno[i]]=1;
 79         }
 80     }
 81 }
 82 
 83 void print(int n)
 84 {
 85     int cnt=0;
 86     for(int i=1;i<=n;i++)
 87         if(!vis[sccno[i]]){
 88             if(cnt==0)printf("%d",i);
 89             else printf(" %d",i);
 90             cnt++;
 91         }
 92         printf("\n");
 93 }
 94 
 95 int main()
 96 {
 97     int n,m;
 98     while(~scanf("%d",&n))
 99     {
100         if(!n)
101             return 0;
102         scanf("%d",&m);
103 
104         init(n);
105         for(int i=0;i<m;i++)
106         {
107             int u,v;
108             scanf("%d%d",&u,&v);
109             add(u,v);
110         }
111 
112         find_scc(n);
113 
114         check(n);
115 
116         print(n);
117     }
118     return 0;
119 }
View Code

 

posted @ 2013-10-03 12:01  Thousand Sunny  阅读(216)  评论(0编辑  收藏  举报