[USACO06JAN]Redundant Paths

OJ题号:
洛谷2860、POJ3177

题目大意:
给定一个无向图,试添加最少的边使得原图中没有桥。

思路:
Tarjan缩点,然后统计度为$1$的连通分量的个数(找出原图中所有的桥)。
考虑给它们每两个连通分量连一条边,这样一次性可以解决两个。
如果最后还有多的,就专门给它随便连一条边。
设度为$1$的连通分量的个数为$c$,则答案为$\lfloor{\frac{c+1}{2}}\rfloor$。
因为是无向图,所以用一般的Tarjan会来回走同一条边,这样就会把桥的两岸缩在同一个点中,不合题意。
考虑Tarjan中记录当前结点的父亲结点,往下递归时判断是否与其相等。这样看起来是正确的,但是交到洛谷上会WA一个点。
因为原图中不一定保证相同的两个点之间只有一条边,因此如果当某两点间同时存在两条边时,不能算桥。但是按照上面的算法不会将这两点缩在一起。
考虑记录每条边的编号,每次递归判断枚举到的出边是否与入边编号相等即可。

 1 #include<stack>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<vector>
 5 inline int getint() {
 6     char ch;
 7     while(!isdigit(ch=getchar()));
 8     int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int V=5001;
13 struct Edge {
14     int to,id;
15 };
16 std::vector<Edge> e[V];
17 inline void add_edge(const int u,const int v,const int id) {
18     e[u].push_back((Edge){v,id});
19 }
20 int dfn[V]={0},low[V]={0},scc[V]={0},cnt=0,id=0;
21 bool ins[V]={0};
22 std::stack<int> s;
23 void Tarjan(const int x,const int eid) {
24     dfn[x]=low[x]=++cnt;
25     s.push(x);
26     ins[x]=true;
27     for(unsigned i=0;i<e[x].size();i++) {
28         if(e[x][i].id==eid) continue;
29         int &y=e[x][i].to;
30         if(!dfn[y]) {
31             Tarjan(y,e[x][i].id);
32             low[x]=std::min(low[x],low[y]);
33         }
34         else if(ins[y]) {
35             low[x]=std::min(low[x],dfn[y]);
36         }
37     }
38     if(low[x]==dfn[x]) {
39         int y;
40         id++;
41         do {
42             y=s.top();
43             s.pop();
44             ins[y]=false;
45             scc[y]=id;
46         } while(y!=x);
47     }
48 }
49 int deg[V]={0};
50 int main() {
51     int n=getint();
52     for(int m=getint();m;m--) {
53         int u=getint(),v=getint();
54         add_edge(u,v,m);
55         add_edge(v,u,m);
56     }
57     for(int i=1;i<=n;i++) {
58         if(!dfn[i]) Tarjan(i,0);
59     }
60     for(int x=1;x<=n;x++) {
61         for(unsigned i=0;i<e[x].size();i++) {
62             int &y=e[x][i].to;
63             if(scc[x]!=scc[y]) deg[scc[x]]++,deg[scc[y]]++;
64         }
65     }
66     int cnt=0;
67     for(int i=1;i<=id;i++) {
68         if(deg[i]==2) cnt++;
69     }
70     printf("%d\n",(cnt+1)>>1);
71     return 0;
72 } 

 

posted @ 2017-08-25 20:39  skylee03  阅读(162)  评论(0编辑  收藏  举报