解题:APIO 2008 免费道路

题面

我们发现我们可以很容易知道最终完成的生成树中有多少鹅卵石路,但是我们不好得到这棵生成树的结构,所以我们尽量“谨慎”地完成生成树·,最好是一点点加到我们要达到的标准而不是通过删掉一些东西来完成

我们把水泥路视为权值为零,鹅卵石路视为权值为一,做最小生成树,这时加入在生成树里的鹅卵石路一定是必须加入的。再然后我们逆着做最小生成树做到恰好有$k$条鹅卵石路,然后用水泥路把图连通起来就好了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=20005,M=100005;
 6 struct a
 7 {
 8     int n1,n2;
 9     int val,imp;
10 }mst[M],outp[N];
11 int aset[N],imp[N];
12 int n,m,c,k,rd,cnt;
13 bool cmp1(a x,a y)
14 {
15     return x.val<y.val;
16 }
17 bool cmp2(a x,a y)
18 {
19     return x.imp==y.imp?x.val>y.val:x.imp>y.imp; 
20 }
21 int find(int x)
22 {
23     return x==aset[x]?x:aset[x]=find(aset[x]);
24 }
25 int main ()
26 {
27     scanf("%d%d%d",&n,&m,&k);
28     for(int i=1;i<=m;i++)
29     {
30         scanf("%d%d%d",&mst[i].n1,&mst[i].n2,&rd);
31         mst[i].imp=false,mst[i].val=rd^1;
32     }
33     for(int i=1;i<=n;i++) aset[i]=i;
34     sort(mst+1,mst+1+m,cmp1);
35     for(int i=1;i<=m;i++)
36     {
37         int f1=find(mst[i].n1),f2=find(mst[i].n2);
38         if(f1!=f2) aset[f1]=f2,mst[i].imp=mst[i].val;
39     }
40     for(int i=1;i<=n;i++) aset[i]=i;
41     sort(mst+1,mst+1+m,cmp2);
42     for(int i=1;i<=m&&c<k;i++)
43     {
44         int f1=find(mst[i].n1),f2=find(mst[i].n2);
45         if(f1!=f2) aset[f1]=f2,c+=mst[i].val,outp[++cnt]=mst[i];
46     }
47     sort(mst+1,mst+1+m,cmp1);
48     for(int i=1;i<=m&&cnt<=n-2;i++)
49     {
50         int f1=find(mst[i].n1),f2=find(mst[i].n2);
51         if(f1!=f2) aset[f1]=f2,c+=mst[i].val,outp[++cnt]=mst[i];
52     }
53     if(c!=k) printf("no solution\n"),exit(0);
54     for(int i=1;i<=cnt;i++)
55         printf("%d %d %d\n",outp[i].n1,outp[i].n2,outp[i].val^1);
56     return 0;
57 }
View Code

 

posted @ 2018-10-24 07:38  Speranza_Leaf  阅读(114)  评论(0)    收藏  举报