POJ2186:利用Tarjan强连通分量求缩点重构图
缩点就是在求出图的所有的强连通分量之后
把强连通分量都看成一个点
这样形成的一个新的图叫做缩点重构图
下面描述一下POJ2186的题意:
给出n个点和m条边(点与点之间的关系),关系具有传递性,问最后有多少点满足其他所有点都能够通达到此
首先我们求出原图的强连通分量
然后将所有的强连通分量缩成点
这样形成的缩点重构图就是一个DAG
DAG中,至少有一个以上的点的出度为0(否则会成环)
然后我们统计出度为0的点的数量
如果这种点的数量大于等于2,那么说明这些点(其实是强连通分量缩成的超级点)之间没有关系,答案为0
如果这种点只有一个,那么这个点所对应的强连通分量中的真实点数就是答案
然后我们看一下做法:
int n,m,cnt,top,sum,deep,ans,tmp1; int g[maxn],dfn[maxn],low[maxn],vis[maxn],st[maxn],col[maxn],deg[maxn],tot[maxn]; struct Edge{int t,next;}e[maxm];
这里面tmp1就是用来记录强连通分量缩成的点中,出度为0的点的数量的
我们重点看一下缩点的过程:
for(u=1;u<=n;u++) { for(int tmp=g[u];tmp;tmp=e[tmp].next) { v=e[tmp].t; if(col[v]!=col[u]) deg[col[u]]++; } tot[col[u]]++; } for(int i=1;i<=sum;i++) if(deg[i]==0) {tmp1++;ans=tot[i];}
首先找出所有超级点的出度
并记录一下这些强连通分量所包含的点的数量
最后根据超级点的出度统计答案就好了
下面给出完整的实现:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=10005; 6 const int maxm=50005; 7 int n,m,cnt,top,sum,deep,ans,tmp1; 8 int g[maxn],dfn[maxn],low[maxn],vis[maxn],st[maxn],col[maxn],deg[maxn],tot[maxn]; 9 struct Edge{int t,next;}e[maxm]; 10 void addedge(int u,int v) 11 { 12 e[++cnt].t=v; 13 e[cnt].next=g[u];g[u]=cnt; 14 } 15 void tarjan(int u) 16 { 17 dfn[u]=low[u]=++deep; 18 vis[u]=1;st[++top]=u; 19 for(int tmp=g[u];tmp;tmp=e[tmp].next) 20 { 21 int v=e[tmp].t; 22 if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);} 23 else if(vis[v]) low[u]=min(low[u],low[v]); 24 } 25 if(dfn[u]==low[u]) 26 { 27 col[u]=++sum; 28 vis[u]=0; 29 while(st[top]!=u) 30 { 31 col[st[top]]=sum; 32 vis[col[top--]]=0; 33 } 34 top--; 35 } 36 } 37 int main() 38 { 39 int u,v; 40 while(scanf("%d%d",&n,&m)!=EOF) 41 { 42 memset(vis,0,sizeof(vis)); 43 memset(deg,0,sizeof(deg)); 44 memset(dfn,0,sizeof(dfn)); 45 memset(tot,0,sizeof(tot)); 46 memset(col,0,sizeof(col)); 47 memset(st,0,sizeof(st)); 48 memset(g,0,sizeof(g)); 49 memset(e,0,sizeof(e)); 50 for(int i=1;i<=m;i++) 51 scanf("%d%d",&u,&v),addedge(u,v); 52 for(int i=1;i<=n;i++) 53 if(!dfn[i]) tarjan(i); 54 for(u=1;u<=n;u++) 55 { 56 for(int tmp=g[u];tmp;tmp=e[tmp].next) 57 { 58 v=e[tmp].t; 59 if(col[v]!=col[u]) deg[col[u]]++; 60 } 61 tot[col[u]]++; 62 } 63 for(int i=1;i<=sum;i++) 64 if(deg[i]==0) {tmp1++;ans=tot[i];} 65 if(tmp1==0) printf("0\n"); 66 else 67 { 68 if(tmp1>1) printf("0\n"); 69 else printf("%d\n",ans); 70 } 71 } 72 return 0; 73 }