码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 3624 免费道路

时间:2018-05-03 23:30:26      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:play   分享图片   思路   col   最小   spl   sdi   bsp   string   

题目大意:

N 个村庄,由 M 条道路连接 其中一些道路是鹅卵石路,而其它道路是水泥路

求一个方案使保留尽可能少的道路,但是两个不同的村庄之间都应该一条且仅由一条且仅由一条免费道路的路径连接且刚好保留K条鹅卵石路

思路:

并查集

先将所有水泥路都加入并查集中

然后找到那些必须被加入的鹅卵石路

再补上其他的鹅卵石路达到k个

最后加上其他水泥路

因为用并查集实现所以最后答案为最小

(写了三个merge贼辣鸡以及一堆细节见代码

技术分享图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #define ll long long 
10 #define MAXN 500100
11 #define inf 2139062143
12 using namespace std;
13 inline int read()
14 {
15     int x=0,f=1;char ch=getchar();
16     while(!isdigit(ch)) {if(ch==-) f=-1;ch=getchar();}
17     while(isdigit(ch)) {x=x*10+ch-0;ch=getchar();}
18     return x*f;
19 }
20 int n,m,k,fa[MAXN],sz,cnt;
21 struct edge {int u,v,c;}e[MAXN];
22 int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
23 //普通合并 
24 void merge(int a,int b)
25 {
26     int x=find(a),y=find(b);
27     if(x!=y) sz--,fa[x]=y;
28 }
29 //带输出及填k个鹅卵石路合并 
30 void Merge(int a,int b,int &z)
31 {
32     int x=find(a),y=find(b);
33     if(x==y) return ;
34     if(!z&&k>0) {fa[x]=y,k--;printf("%d %d %d\n",a,b,z);z=1;}
35     else if(z) {fa[x]=y;printf("%d %d %d\n",a,b,z);}
36 }
37 //记录需要的鹅卵石路及填k个鹅卵石路合并 
38 void MergE(int a,int b,int &z)
39 {
40     int x=find(a),y=find(b);
41     if(x==y||k==0) return ;
42     fa[x]=y,k--,z=-1,sz--;
43 }
44 int main()
45 {
46     n=read(),m=read(),k=read(),sz=n;
47     for(int i=1;i<=n;i++) fa[i]=i;
48     for(int i=1;i<=m;i++) {e[i].u=read(),e[i].v=read(),e[i].c=read(),cnt+=e[i].c;merge(e[i].u,e[i].v);}
49     if(m-cnt<k||sz>1||n==1) {puts("no solution");return 0;}//鹅卵石路不够k个或者所有路都无法把所有点联通 
50     for(int i=1;i<=n;i++) fa[i]=i;sz=n;
51     for(int i=1;i<=m;i++) if(e[i].c) merge(e[i].u,e[i].v);
52     //求出必须的鹅卵石路 
53     for(int i=1;i<=m;i++)
54         if(!e[i].c) MergE(e[i].u,e[i].v,e[i].c);
55     if(sz>1) {puts("no solution");return 0;}//必须的鹅卵石路比k个多
56     for(int i=1;i<=n;i++) fa[i]=i;
57     for(int i=1;i<=m;i++)
58         if(e[i].c<0) merge(e[i].u,e[i].v);
59     //求出其他鹅卵石路 
60     for(int i=1;i<=m;i++)
61         if(!e[i].c) MergE(e[i].u,e[i].v,e[i].c);
62     if(k) {puts("no solution");return 0;}//鹅卵石路形成的无环图达不到k个 
63     for(int i=1;i<=m;i++) 
64         if(e[i].c<0) printf("%d %d 0\n",e[i].u,e[i].v);
65     for(int i=1;i<=m;i++)
66         if(e[i].c>0) Merge(e[i].u,e[i].v,e[i].c);
67 }
View Code

 

bzoj 3624 免费道路

标签:play   分享图片   思路   col   最小   spl   sdi   bsp   string   

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/8987880.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!