【Kruskal+贪心思想】BZOJ3624-[Apio2008]免费道路
国庆万岁!!!!!
【题目大意】
给定一张无向图,有两种边的类型为0和1。求一个最小生成树使得边0有k条。
【思路】
跑两次Kruskal。
第一次的时候优先选择边1,然后判断有哪些边0还不能连通,那么这些边0是必须要选取的。如果必须要选的边0大于k,那么直接输出无解。
第二次的时候先合并那么必须要选取的边0,然后在剩下的边0中左右还没有连通的里选取。如果把所有都选上了之后边0的数量还是没有到k,那么直接输出无解。
截下来按照普通Kruskal的方法把边1合并掉。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 const int MAXN=20000+50; 8 const int MAXM=100000+50; 9 struct Edge 10 { 11 int u,v; 12 }edge[MAXM]; 13 int n,m,k; 14 int vis[MAXM]; 15 int L,R; 16 int fa[MAXN],h[MAXN]; 17 vector<int> mustchoose; 18 19 void initset(){for (int i=1;i<=n;i++) fa[i]=i,h[i]=1;} 20 21 int find(int x) 22 { 23 int r=x; 24 while (fa[r]!=r) r=fa[r]; 25 while (fa[x]!=r) 26 { 27 int tmp=fa[x]; 28 fa[x]=r; 29 x=fa[x]; 30 } 31 return r; 32 } 33 34 void unionset(int a,int b) 35 { 36 if (h[a]>=h[b]) 37 { 38 fa[b]=a; 39 if (h[a]==h[b]) h[a]++; 40 } 41 else fa[a]=b; 42 } 43 44 void init() 45 { 46 scanf("%d%d%d",&n,&m,&k); 47 L=0,R=m+1; 48 for (int i=1;i<=m;i++) 49 { 50 int u,v,c; 51 scanf("%d%d%d",&u,&v,&c); 52 if (c) edge[++L]=(Edge){u,v}; 53 else edge[--R]=(Edge){u,v}; 54 } 55 } 56 57 void solve() 58 { 59 int t=0; 60 initset(); 61 for (int i=1;i<=m;i++) 62 { 63 int fa=find(edge[i].u),fb=find(edge[i].v); 64 if (fa!=fb) 65 { 66 unionset(fa,fb); 67 if (i>=R) 68 { 69 vis[i]=1; 70 t++; 71 mustchoose.push_back(i); 72 } 73 } 74 } 75 if (t>k) 76 { 77 puts("no solution"); 78 return; 79 } 80 // 找出必须要选择的鹅卵石路 81 82 initset(); 83 for (int i=0;i<mustchoose.size();i++) 84 { 85 int fa=find(edge[mustchoose[i]].u),fb=find(edge[mustchoose[i]].v); 86 unionset(fa,fb); 87 } 88 for (int i=R;i<=m;i++) 89 if (t<k && !vis[i]) 90 { 91 int fa=find(edge[i].u),fb=find(edge[i].v); 92 if (fa!=fb) 93 { 94 unionset(fa,fb); 95 vis[i]=1; 96 t++; 97 } 98 } 99 if (t<k) 100 { 101 puts("no solution"); 102 return; 103 } 104 //先选择必须要的鹅卵石路,然后再用其他鹅卵石路填充 105 106 for (int i=1;i<=L;i++) 107 { 108 int fa=find(edge[i].u),fb=find(edge[i].v); 109 if (fa!=fb) 110 { 111 unionset(fa,fb); 112 vis[i]=1; 113 } 114 } 115 for (int i=1;i<=L;i++) if (vis[i]) printf("%d %d %d\n",edge[i].u,edge[i].v,1); 116 for (int i=R;i<=m;i++) if (vis[i]) printf("%d %d %d\n",edge[i].u,edge[i].v,0); 117 } 118 119 int main() 120 { 121 init(); 122 solve(); 123 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
2015-10-01 【SPFA】POJ3259-Wormhole