BZOJ 3624: [Apio2008]免费道路
3624: [Apio2008]免费道路
Time Limit: 2 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 1201 Solved: 469
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
5 7 2
1 3 0
4 5 1
3 2 0
5 3 1
4 3 0
1 2 1
4 2 1
1 3 0
4 5 1
3 2 0
5 3 1
4 3 0
1 2 1
4 2 1
Sample Output
3 2 0
4 3 0
5 3 1
1 2 1
4 3 0
5 3 1
1 2 1
HINT
Source
哎呀,这题好气啊,明明不难的,就是想不到啊,还是我太蒟蒻了啊。
题意要求我们求出一棵生成树,但是这次限制的不是权值大小,而是在一个给定的边集的子集中选出恰好K条边加入生成树,输出任意一种方案即可,SPJ。
这个其实很简单,你就先紧着子集里的边加,做Kruskal,求出一棵生成树(也许只能做出一棵生成森林),这是你保证了子集中选出的边>=K(如果小于K那就是无解啦),这时先用子集外的边填补漏洞,把森林补成树(补不成就是无解啦),然后再不断尝试加入子集外的边,显然加入之后会有环,那么替换掉环上的一条子集边即可(如果环上有的话),这个用LCT维护就好了,反正N<=20000是吧。
其实上面只是开玩笑的,如果你真的像我一开始这么想,看到Time Limit你就绝望了,23333——手动滑稽
正解是先紧着子集外的边加,造一个森林(能是树最好啦),然后用子集内的边补上不连通的位置。如果不能补成树或使用的子集边>K,那么就是无解。那么此时用来填补非子集边无法做到的联通性的边(就是刚才选出来的子集边)是一定要选的(并非必须边,但是一定存在一组可行解包含它们)。那么先选上这些,下面我们一定可以用非子集边把图连成生成树了,但是可能子集边还不到K,那就再随便选几个啦,然后再用非子集填补空缺。
1 #include <cstdio> 2 3 const int mxn = 20005; 4 const int mxm = 100005; 5 6 int n, m, k; 7 8 struct edge 9 { 10 int x, y, c; 11 }e[mxm]; 12 13 int fa[mxn]; 14 15 int find(int u) 16 { 17 return u == fa[u] ? u : fa[u] = find(fa[u]); 18 } 19 20 bool vis[mxm]; 21 22 signed main(void) 23 { 24 scanf("%d%d%d", &n, &m, &k); 25 26 for (int i = 1; i <= m; ++i) 27 scanf("%d%d%d", 28 &e[i].x, 29 &e[i].y, 30 &e[i].c); 31 32 bool possible = true; 33 34 { 35 int cnt = 0, root; 36 37 for (int i = 1; i <= n; ++i)fa[i] = i; 38 39 for (int i = 1; i <= m; ++i) 40 if (e[i].c) 41 { 42 int fx = find(e[i].x); 43 int fy = find(e[i].y); 44 45 if (fx != fy) 46 fa[fx] = fy; 47 } 48 49 for (int i = 1; i <= m; ++i) 50 if (!e[i].c) 51 { 52 int fx = find(e[i].x); 53 int fy = find(e[i].y); 54 55 if (fx != fy) 56 fa[fx] = fy, ++cnt, vis[i] = true; 57 } 58 59 if (cnt > k) 60 possible = false; 61 62 root = find(1); 63 64 for (int i = 2; i <= n; ++i) 65 if (find(i) != root) 66 possible = false; 67 68 k -= cnt; 69 } 70 71 if (!possible) 72 return puts("no solution"), 0; 73 74 { 75 for (int i = 1; i <= n; ++i)fa[i] = i; 76 77 for (int i = 1; i <= m; ++i) 78 if (vis[i]) 79 { 80 int fx = find(e[i].x); 81 int fy = find(e[i].y); 82 83 fa[fx] = fy; 84 } 85 86 for (int i = 1; i <= m; ++i) 87 if (!e[i].c && !vis[i] && k) 88 { 89 int fx = find(e[i].x); 90 int fy = find(e[i].y); 91 92 if (fx != fy) 93 fa[fx] = fy, vis[i] = true, --k; 94 } 95 96 for (int i = 1; i <= m; ++i) 97 if (e[i].c) 98 { 99 int fx = find(e[i].x); 100 int fy = find(e[i].y); 101 102 if (fx != fy) 103 fa[fx] = fy, vis[i] = true; 104 } 105 } 106 107 for (int i = 1; i <= m; ++i) 108 if (vis[i])printf("%d %d %d\n", e[i].x, e[i].y, e[i].c); 109 }
@Author: YouSiki