3624: [Apio2008]免费道路
3624: [Apio2008]免费道路
https://www.lydsy.com/JudgeOnline/problem.php?id=3624
题意:
一张无向图,每种边有两种类型0和1。求一个最小生成树使得有k条0边。
分析:
为了满足有k条0边的限制,先考虑0边哪些必选,如果所有1边都加入后,还有0边可以使得图不连通,那么这些0边必须选。
把必须选的加上然后再加到k,然后再加1边。中间判一下是否必选的大于k,0边是否大于等于k。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 20010; 11 const int M = 100010; 12 13 struct Edge{ 14 int u,v; 15 Edge() {} 16 Edge(int a,int b) {u = a, v = b;} 17 }e[M]; 18 int fa[N], q[M]; 19 bool vis[M]; 20 21 int find(int x) { 22 return x == fa[x] ? x : fa[x] = find(fa[x]); 23 } 24 25 int main () { 26 27 int n = read(), m = read(), k = read(); 28 29 int B = 0, W = m + 1; 30 for (int i=1; i<=m; ++i) { 31 int u = read(), v = read(), c = read(); 32 if (c == 1) e[++B] = Edge(u,v); 33 else e[--W] = Edge(u,v); 34 } 35 36 for (int i=1; i<=n; ++i) fa[i] = i; 37 38 int tot = 0; 39 for (int i=1; i<=m; ++i) { 40 int u = find(e[i].u), v = find(e[i].v); 41 if (u == v) continue; 42 fa[u] = v; 43 if (i > B) vis[i] = true, q[++tot] = i; 44 } 45 46 if (tot > k) { 47 puts("no solution"); 48 return 0; 49 } 50 51 for (int i=1; i<=n; ++i) fa[i] = i; 52 53 for (int i=1; i<=tot; ++i) 54 fa[find(e[q[i]].u)] = find(e[q[i]].v); 55 56 for (int i=W; i<=m; ++i) { 57 if (tot == k) break; 58 int u = find(e[i].u), v = find(e[i].v); 59 if (u == v) continue; 60 fa[u] = v; 61 tot ++; 62 vis[i] = true; 63 } 64 65 if (tot < k) { 66 puts("no solution"); 67 return 0; 68 } 69 70 for (int i=1; i<=B; ++i) { 71 int u = find(e[i].u), v = find(e[i].v); 72 if (u == v) continue; 73 fa[u] = v; 74 vis[i] = true; 75 } 76 77 for (int i=1; i<=m; ++i) 78 if (vis[i]) printf("%d %d %d\n", e[i].u, e[i].v, i<=B?1:0); 79 80 return 0; 81 }