Codeforces Beta Round #25 (Div. 2 Only) D. Roads not only in Berland(DFS+并查集)
题目大意
给了一个无向图,n(2<=n<=1000) 个节点 n-1 条边,每天拆一条边并新建一条边,最终使得所有的顶点连通(其实形成一棵树)
问:最少需要几天,并且输出每天拆掉的边和新建的边
做法分析
首先,我们可以把每条边存下来,然后利用 DFS,遍历所有的顶点一遍,遍历的过程中,经过的边就是树边(也就是所有的不拆掉的边),剩下的所有边统统要拆掉
利用并查集,把每个连通块用一个点代表,并统计这个连通快中需要删掉的边的个数(DFS过程中没有遍历到的边的个数)
这里,我们需要注意到这样一个性质:只有 n-1 条边,那么,图中肯定存在一个联通快,它是一棵树或者一个孤立的节点
最少需要的天数肯定是不能遍历到的边的数量
那么:每一天,我们删掉一条没有遍历到的边,从这个连通块中,并引一条边出去到另一个全是树边的连通分量,注意更新删掉边以后那个连通分量的相关信息
参考代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7 const int N=1006; 8 9 struct Edge 10 { 11 int s, t, next; 12 bool flag; 13 void init(int a, int b, int c) 14 { 15 s=a, t=b, next=c, flag=false; 16 } 17 } edge[N*2]; 18 int head[N], tot; 19 20 void add_edge(int s, int t) 21 { 22 edge[tot].init(s, t, head[s]); 23 head[s]=tot++; 24 edge[tot].init(t, s, head[t]); 25 head[t]=tot++; 26 } 27 28 int n, cnt[N], fa[N]; 29 bool vs[N]; 30 31 void DFS(int u, int pre) 32 { 33 vs[u]=1; 34 for(int e=head[u]; e!=-1; e=edge[e].next) 35 { 36 int v=edge[e].t; 37 if(v==pre || vs[v]) continue; 38 edge[e].flag=1, edge[e^1].flag=1; 39 DFS(v, u); 40 } 41 } 42 43 int find_fa(int x) 44 { 45 if(fa[x]!=x) fa[x]=find_fa(fa[x]); 46 return fa[x]; 47 } 48 49 int main() 50 { 51 scanf("%d", &n); 52 memset(head, -1, sizeof head); 53 tot=0; 54 for(int i=1; i<=n; i++) fa[i]=i; 55 for(int i=1, a, b; i<n; i++) 56 { 57 scanf("%d%d", &a, &b); 58 add_edge(a, b); 59 int f1=find_fa(a); 60 int f2=find_fa(b); 61 if(f1!=f2) fa[f1]=f2; 62 } 63 memset(vs, 0, sizeof vs); 64 for(int i=1; i<=n; i++) if(!vs[i]) DFS(i, -1); 65 66 memset(cnt, 0, sizeof cnt); 67 int ans=0; 68 for(int i=0; i<tot; i+=2) if(!edge[i].flag) 69 { 70 ans++; 71 cnt[find_fa(edge[i].s)]++, cnt[find_fa(edge[i].t)]++; 72 } 73 74 printf("%d\n", ans); 75 for(int e=0; e<tot; e+=2) 76 { 77 if(edge[e].flag) continue; 78 printf("%d %d ", edge[e].s, edge[e].t); 79 for(int i=1; i<=n; i++) 80 { 81 if(cnt[find_fa(i)]!=0 || find_fa(i)==find_fa(edge[e].s)) continue; 82 printf("%d %d\n", edge[e].s, i); 83 fa[find_fa(i)]=find_fa(edge[e].s); 84 break; 85 } 86 cnt[find_fa(edge[e].s)]--, cnt[find_fa(edge[e].t)]--; 87 } 88 return 0; 89 }
题目链接 & AC通道
Codeforces Beta Round #25 (Div. 2 Only) D. Roads not only in Berland