首页 > Windows开发 > 详细

[luogu]P3623 [APIO2008]免费道路

时间:2018-11-27 10:05:55      阅读:146      评论:0      收藏:0      [点我收藏+]

原题链接:P3623 [APIO2008]免费道路

题意

给定一个图(不一定连通),上面有$m$条$0$边和$1$边。

要求选边使图连通,$0$边的数量必须等于$k$。

 

分析

一开始用很天真的想法加边:先加鹅卵石路,一直加到$k$条。然后再加水泥路,加到满。

然后发现在洛谷上WA了一个点。

仔细分析一下问题:一对点,如果我们加的是鹅卵石路,那么我们本可以用水泥路使这一对点连通,我们现在却使用了一次鹅卵石名额,这样子可能会导致后面鹅卵石名额不足。

那么怎么考虑这个问题呢?

我们发现只有用鹅卵石代替了水泥才会导致名额的冲突,那么我们只要求出有多少名额是必须给的(不给就不能连通的),然后优先给它们名额。

至于剩下的,就先把鹅卵石的名额加到$k$,然后再加水泥路加到满就可以了。

 

代码

技术分享图片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e5+1000,M=3e5+1000;
 4 struct edge{
 5     int x,y;
 6 }sn[M],er[M];
 7 int read(){
 8     char c;int num,f=1;
 9     while(c=getchar(),!isdigit(c))if(c==-)f=-1;num=c-0;
10     while(c=getchar(), isdigit(c))num=num*10+c-0;
11     return f*num;
12 }
13 int n,m,k,pre[N];
14 int tot1=0,tot2=0,ans=0;
15 int pt[M][4],vis[M];
16 int fid(int x){return (x==pre[x])?x:(pre[x]=fid(pre[x]));}
17 int main()
18 {
19     n=read();m=read();
20     k=read();
21     for(int i=1;i<=m;i++){
22         int u,v,w;
23         u=read();v=read();
24         w=read();
25         if(w==1){
26             sn[++tot1].x=u;
27             sn[  tot1].y=v;
28         }else{
29             er[++tot2].x=u;
30             er[  tot2].y=v;
31         }
32     }
33     if(tot2<k)goto no;
34     int tt=0;
35     for(int i=1;i<=n;i++)pre[i]=i;
36     for(int i=1;i<=tot1;i++){
37         if(fid(sn[i].x)!=fid(sn[i].y)){
38             pre[fid(sn[i].x)]=fid(sn[i].y);
39             tt++;
40         }
41     }
42     int num=0;
43     for(int i=1;i<=tot2;i++){
44         if(fid(er[i].x)!=fid(er[i].y)){
45             pre[fid(er[i].x)]=fid(er[i].y);
46             vis[i]=1;
47             num++;tt++;
48         }
49     }
50     if(tt<n-1||num>k)goto no;
51 
52     for(int i=1;i<=n;i++)pre[i]=i;
53     for(int i=1;i<=tot2;i++){
54         if(vis[i]){
55             pre[fid(er[i].x)]=fid(er[i].y);
56             pt[++ans][1]=er[i].x;
57             pt[  ans][2]=er[i].y;
58             pt[  ans][3]=0;
59             if(ans==k)break;
60         }
61     }
62     for(int i=1;i<=tot2;i++){
63         if(vis[i])continue;
64         if(fid(er[i].x)!=fid(er[i].y)){
65             pre[fid(er[i].x)]=fid(er[i].y);
66             pt[++ans][1]=er[i].x;
67             pt[  ans][2]=er[i].y;
68             pt[  ans][3]=0;
69             if(ans==k)break;
70         }
71     }
72     if(ans<k)goto no;
73     for(int i=1;i<=tot1;i++){
74         if(fid(sn[i].x)!=fid(sn[i].y)){
75             pre[fid(sn[i].x)]=fid(sn[i].y);
76             pt[++ans][1]=sn[i].x;
77             pt[  ans][2]=sn[i].y;
78             pt[  ans][3]=1;
79             if(ans==n-1)break;
80         }
81     }
82     if(ans<n-1)goto no;
83     for(int i=1;i<=ans;i++)
84         printf("%d %d %d\n",pt[i][1],pt[i][2],pt[i][3]);
85     return 0;
86 no:
87     printf("no solution\n");
88     return 0;
89 }
View Code

 

[luogu]P3623 [APIO2008]免费道路

原文:https://www.cnblogs.com/onglublog/p/10024242.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!