BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
来源:互联网 发布:网络数据论文 编辑:程序博客网 时间:2024/06/05 09:52
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[N], v[N], w[N], c[N], fa[N];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;}
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- BZOJ 2654 tree 二分+最小生成树
- bzoj 2654: tree 二分+最小生成树
- BZOJ 2654: tree 最小生成树+二分
- bzoj 2654: tree (二分+最小生成树)
- bzoj 2654 tree (二分 + 最小生成树)
- BZOJ 2654 tree(二分答案+最小生成树)
- BZOJ 2654: tree kruskal 二分
- BZOJ[2654]Tree 二分+Kruskal
- 【BZOJ】2654 tree 二分+kruskal
- BZOJ-1196 公路修建问题 最小生成树Kruskal+(二分??)
- BZOJ 2654 tree 二分答案+Kruskal
- BZOJ 2654 二分+最小生成树
- [BZOJ 1016][JSOI2008]最小生成树计数(Kruskal)
- BZOJ 2429 聪明的猴子 (最小生成树 kruskal)
- BZOJ 1016 最小生成树计数 Kruskal
- [bzoj2654]tree(二分+最小生成树)
- bzoj2654: tree(二分+最小生成树)
- 浅谈jQuery Pagination Ajax 分页插件的使用
- tp5存储公司信息
- c++ vector reserve/resize解析
- iOS中textfield有效限制输入长度
- CSS揭秘(背景与边框)
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- 使用axis1.4来生成Webservice的java客户端
- mybatis中resultMap和resultType详解
- 数据库索引详解
- Android动画分类介绍使用
- 压缩图片(-)
- 微信小程序 Node.js (基础十一) 全局对象
- 面向委托关联的js代码应用实例
- 赌场21点游戏