【UVA10972】RevolC FaeLoN (求边双联通分量)

题意:

  给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通。

分析:

  这题的解法还是很好想的。先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans+2,为1则ans+1,最后输出(ans+1)/2。

  注意,如果原图本来就强联通,答案为0不是1。

在这里主要说说打边双联通的注意事项。(一开始觉得是跟点双连通差不多的,调试的时候才发现很容易疏忽导致BUG很多啊)

1、如果有重边,则那条就不是割边了,我们很容易向上重走树枝边的反向边导致程序认为这是返祖边。在点双连通中判断一下是不是父亲即可,但边双联通不行。(因为重边对点双连通无影响,但对边双联通有影响)所以要做一个标记,走树枝边的时候把反向边也标记一下。

2、stack中的剩余元素最后要记得pop出来。

3、图不一定联通,要for一遍再dfs。

4、发现(x,y)为割边的时候,(dfn[x]<dfn[y]),边双联通分量是算到y而不是x。(跟点双连通有一点不一样)

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<stack>
 7 using namespace std;
 8 #define Maxn 1010
 9 
10 struct node
11 {
12     int x,y,next;
13     bool vis;
14 }t[2*Maxn*Maxn];int len;
15 
16 int first[Maxn],n,m;
17 int dfn[Maxn],low[Maxn],cnt;
18 int cc[Maxn],cl,sum[Maxn];
19 stack<int > s;
20 
21 void ins(int x,int y)
22 {
23     t[++len].x=x;t[len].y=y;t[len].vis=0;
24     t[len].next=first[x];first[x]=len;
25 }
26 
27 int mymin(int x,int y) {return x<y?x:y;}
28 
29 void ffind(int x)
30 {
31     dfn[x]=low[x]=++cnt;
32     s.push(x);
33     for(int i=first[x];i;i=t[i].next) if(!t[i].vis)
34     {
35         int y=t[i].y;
36         t[i].vis=1;t[i+(i%2==1?1:-1)].vis=1;
37         if(!dfn[y])
38         {
39             ffind(y);
40             low[x]=mymin(low[x],low[y]);
41             if(low[y]>dfn[x])
42             {
43                 cl++;
44                 while(!s.empty())
45                 {
46                     int z=s.top();
47                     s.pop();
48                     cc[z]=cl;
49                     if(z==y) break;
50                 }
51             }
52         }
53         else low[x]=mymin(low[x],dfn[y]);
54     }
55 }
56 
57 int main()
58 {
59     while(scanf("%d%d",&n,&m)!=EOF)
60     {
61         len=0;cnt=0;cl=0;
62         memset(first,0,sizeof(first));
63         memset(dfn,0,sizeof(dfn));
64         memset(cc,0,sizeof(cc));
65         memset(sum,0,sizeof(sum));
66         for(int i=1;i<=m;i++)
67         {
68             int x,y;
69             scanf("%d%d",&x,&y);
70             ins(x,y);ins(y,x);
71         }
72         if(!s.empty()) s.pop();
73         for(int i=1;i<=n;i++)if(!dfn[i])
74         {
75             ffind(i);
76             if(!s.empty())
77             {
78                 cl++;
79                 while(!s.empty())
80                 {
81                     cc[s.top()]=cl;
82                     s.pop();
83                 }
84             }
85         }
86          if(cl==1) {printf("0
");continue;}
87         
88         int ans=0;
89         for(int i=1;i<=len;i++)
90         {
91             if(cc[t[i].x]==cc[t[i].y]) continue;
92             sum[cc[t[i].x]]++;
93         }
94         for(int i=1;i<=cl;i++) if(sum[i]==1) ans++;
95         else if(sum[i]==0) ans+=2;
96         printf("%d
",(ans+1)/2);
97     }
98     return 0;
99 }
[uva10972]

2016-03-23 13:54:57

原文地址:https://www.cnblogs.com/Konjakmoyu/p/5310811.html