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 }

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9429142.html
今日推荐