bzoj 3624 免费道路

Posted jack_yyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3624 免费道路相关的知识,希望对你有一定的参考价值。

题目大意:

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 免费道路的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3624,[Apio2008]免费道路

bzoj 3624 免费道路

BZOJ 3624 免费道路

bzoj3624Apio2008—免费道路

Bzoj 3624: [Apio2008]免费道路 (贪心+生成树)

BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]