BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
2017-07-05 20:33
344 查看
BZOJ 2654 tree
Description给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行
每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
Sample Output
2
HINT
数据规模和约定
0:V<=10
1,2,3:V<=15
0,..,19:V<=50000,E<=100000
所有数据边权为[1,100]中的正整数。
思路:
巧妙,
我们发现,如果考虑权值,那么就没有办法处理黑白,如果考虑黑白,那么又做不到权值的最优。
所以我们冥思苦想如何把黑白区分开,又不能改变权值之间的优劣。于是就有了一个神奇的解法,如果我们给白边增加权值,那么求最小生成树时,由于白边权值增大,所有不容易选白边。
这样一来,我们既没有改变他们权值的顺序,而且白边选的就会少一点,最小生成树有保证了当前状态下的最优解。
记f(x)为给白边增加x权值,求出最小生成树后,白边的数量,又可以发现,f(x)随x增大而减小,所以二分x的值。
可能有人会疑惑,有可能x在[a,b]中都满足白边数目为need,这个时候x与ans(树的大小)之间并没有单调关系,怎么能二分呢?针对这道题,只要我们找到了满足白边数目为need的状态,那么它就是答案。为什么?因为我们的ans只与选了那些边有关,x我们最终是要剪掉的,又因为保证了need条白边,所以剩下的选择都是黑边了,而黑边是不受x影响的,所以只要满足了need,那么就是答案。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define lim 1000 #define ll long long using namespace std; const int N = 100005; int n, m, cnt, tot, goal, ans; int u , v , w , c , fa ; struct edge{ int u, v, w, c; }ed[N<<1]; bool cmp(edge a, edge b){ if(a.w == b.w) return a.c < b.c;//优先白 else return a.w < b.w; } int find(int x){ if(x == fa[x]) return x; else return fa[x] = find(fa[x]); } bool check(int x){ tot = cnt = 0; for(int i=1; i<=n; i++) fa[i] = i; for(int i=1; i<=m; i++){ ed[i].u = u[i]; ed[i].v = v[i]; ed[i].w = w[i]; ed[i].c = c[i]; if( !c[i] ) ed[i].w += x; } sort(ed+1, ed+m+1, cmp); for(int i=1; i<=m; i++){//kruskal int p = find(ed[i].u), q = find(ed[i].v); if(p != q){ fa[p] = q; tot += ed[i].w; if( !ed[i].c ) cnt++; } } return cnt >= goal; } int main(){ scanf("%d%d%d", &n, &m, &goal); for(int i=1; i<=m; i++){ scanf("%d%d%d%d", &u[i], &v[i], &w[i], &c[i]); u[i]++; v[i]++;//更改编号为1开始,方便check } int l=-lim, r=lim; while(l <= r){//二分 int mid = (l + r) >> 1; if( check(mid) ){ l = mid + 1; ans = tot - goal * mid;//还原 } else r = mid - 1; } printf("%d", ans); return 0; }
相关文章推荐
- 【二分+最小生成树】BZOJ2654 tree
- BZOJ2654 tree 【二分 + 最小生成树】
- [bzoj2654]tree 二分+最小生成树
- BZOJ 2654: tree 最小生成树+二分
- 【二分+最小生成树】BZOJ2654[tree]题解
- [bzoj2654][最小生成树][二分]tree
- bzoj2654: tree(二分+最小生成树)
- 【BZOJ2654】tree 二分+最小生成树
- 【bzoj2654】【tree】【二分+最小生成树】
- [bzoj2654]tree(最小生成树+二分)
- bzoj 2654: tree 二分+最小生成树
- BZOJ 2654 tree 二分+最小生成树
- 【二分+最小生成树】bzoj2654 tree
- bzoj 2654 tree (二分 + 最小生成树)
- 【bzoj2654】【二分+最小生成树】tree
- 二分+最小生成树【bzoj2654】: tree
- BZOJ 2654 tree(二分答案+最小生成树)
- 【BZOJ2654】tree【二分】【最小生成树】
- BZOJ 2654 tree - 二分+最小生成树
- [bzoj2654]tree(二分+最小生成树)