APIO2008 洛谷P3623 免费道路

题目传送门:https://www.luogu.org/recordnew/show/6743108

题解:写3次并查集,首先不妨留下所有水泥路,添加石子路,那么添加的石子路一定在答案内,留下所有石子路也一样,最后再添加其他边是等价的,注意k值即可,注意要判断好几次无解的情况。

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define MN 20005
 4 #define MM 100005
 5 using namespace std;
 6 int n,m,k,fa[MN],u[MM],v[MM],c[MM],ans[MM],cnt;
 7 bool used[MM];
 8 int ff(int x){return fa[x]==x?x:fa[x]=ff(fa[x]);}
 9 bool check(){
10     int tmp=ff(1);
11     for(int i=2;i<=n;i++)
12         if(ff(i)!=tmp) return false;
13     return true;
14 }
15 bool work1(){
16     for(int i=1;i<=n;i++) fa[i]=i;
17     for(int i=1;i<=m;i++)
18         if(c[i]){
19             int x=ff(u[i]),y=ff(v[i]);
20             if(x!=y) fa[y]=x;
21         }
22     for(int i=1;i<=m;i++)
23         if(!c[i]){
24             int x=ff(u[i]),y=ff(v[i]);
25             if(x!=y) fa[y]=x,ans[++cnt]=i,used[i]=true;
26         }
27     if(k<cnt) return false;
28     else k-=cnt;
29     if(!check()) return false;
30     return true;
31 }
32 bool work2(){
33     for(int i=1;i<=n;i++) fa[i]=i;
34     for(int i=1;i<=m;i++)
35         if(!c[i]){
36             int x=ff(u[i]),y=ff(v[i]);
37             if(x!=y) fa[y]=x;
38         }
39     for(int i=1;i<=m;i++)
40         if(c[i]){
41             int x=ff(u[i]),y=ff(v[i]);
42             if(x!=y) fa[y]=x,ans[++cnt]=i,used[i]=true;
43         }
44     if(!check()) return false;
45     return true;
46 }
47 bool work3(){
48     for(int i=1;i<=n;i++) fa[i]=i;
49     for(int i=1;i<=cnt;i++){
50         int x=ff(u[ans[i]]),y=ff(v[ans[i]]);
51         if(x!=y) fa[y]=x;
52         else return false;
53     }
54     for(int i=1;i<=m;i++){
55         if(!k) break;
56         if(!used[i]&&!c[i]){
57             int x=ff(u[i]),y=ff(v[i]);
58             if(x!=y) fa[y]=x,k--,ans[++cnt]=i;
59         }
60     }
61     if(k) return false;
62     for(int i=1;i<=m;i++)
63         if(!used[i]&&c[i]){
64             int x=ff(u[i]),y=ff(v[i]);
65             if(x!=y) fa[y]=x,ans[++cnt]=i;
66         }
67     if(!check()) return false;
68     return true;
69 }
70 int main()
71 {
72     scanf("%d%d%d",&n,&m,&k);
73     for(int i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&c[i]);
74     if(!work1()){puts("no solution");return 0;}
75     if(!work2()){puts("no solution");return 0;}
76     if(!work3()){puts("no solution");return 0;}
77     for(int i=1;i<=cnt;i++)
78         printf("%d %d %d
",u[ans[i]],v[ans[i]],c[ans[i]]);
79     return 0;
80 }
原文地址:https://www.cnblogs.com/Beginner-/p/8798900.html