BZOJ 2654 二分+最小生成树
2017-07-05 09:10
169 查看
2654: tree
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
Sample Output
2
【解题报告】
显然可以发现随着白边权值的增大。最小生成树中白边的个数不增。
然后根据这个性质我们就可以二分一个值,然后每次给白边加上这个值。看一下最小生成树中白边的个数。
最后答案再把它减去。
看起来思路非常简单,但是有一个很重要的细节。
如果在你的二分过程中如果给白边加上mid,你得到的白边数比need大。
给白边加上mid+1,你得到的白边比need小。
这种情况看似没法处理。
但是考虑一下克鲁斯卡尔的加边顺序。
可以发现如果出现这种情况,一定是有很多相等的白边和黑边。因为数据保证合法。
所以我们可以把一些白边替换成黑边。
所以我们要在白边数>=need的时候跟新答案。
具体用sumv=tot-ned*mid即可。
代码如下:
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
Sample Output
2
【解题报告】
显然可以发现随着白边权值的增大。最小生成树中白边的个数不增。
然后根据这个性质我们就可以二分一个值,然后每次给白边加上这个值。看一下最小生成树中白边的个数。
最后答案再把它减去。
看起来思路非常简单,但是有一个很重要的细节。
如果在你的二分过程中如果给白边加上mid,你得到的白边数比need大。
给白边加上mid+1,你得到的白边比need小。
这种情况看似没法处理。
但是考虑一下克鲁斯卡尔的加边顺序。
可以发现如果出现这种情况,一定是有很多相等的白边和黑边。因为数据保证合法。
所以我们可以把一些白边替换成黑边。
所以我们要在白边数>=need的时候跟新答案。
具体用sumv=tot-ned*mid即可。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100005 int n,m,ned; int sumv,tot,cnt; int fa ; struct Edge { int u,v,w,c; }e ; bool cmp(Edge a,Edge b) {return a.w==b.w?a.c<b.c:a.w<b.w;} int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);} bool check(int x) { tot=0,cnt=0; for(int i=1;i<=n;++i) fa[i]=i; for(int i=1;i<=m;++i) if(!e[i].c) e[i].w+=x; sort(e+1,e+m+1,cmp); for(int i=1;i<=m;++i) { int p=find(e[i].u),q=find(e[i].v); if(p!=q) { fa[p]=q; tot+=e[i].w; if(!e[i].c) ++cnt; } } for(int i=1;i<=m;++i) if(!e[i].c) e[i].w-=x; return cnt>=ned; } int main() { scanf("%d%d%d",&n,&m,&ned); for(int i=1;i<=m;++i) { scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w,&e[i].c); ++e[i].u,++e[i].v; } int l=-105,r=105; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) l=mid+1,sumv=tot-ned*mid; else r=mid-1; } printf("%d\n",sumv); return 0; }
相关文章推荐
- 二分+最小生成树【bzoj2654】: tree
- 【BZOJ2654】tree【二分】【最小生成树】
- BZOJ 2654: tree 最小生成树+二分
- BZOJ 2654 tree(二分答案+最小生成树)
- 【二分+最小生成树】bzoj2654 tree
- bzoj 2654 tree (二分 + 最小生成树)
- 【bzoj2654】【二分+最小生成树】tree
- 【二分+最小生成树】BZOJ2654 tree
- bzoj2654: tree(二分+最小生成树)
- bzoj2654 二分答案+最小生成树
- bzoj 2654: tree 二分+最小生成树
- BZOJ 2654 tree - 二分+最小生成树
- 【bzoj2654】【tree】【二分+最小生成树】
- bzoj2654 二分+最小生成树
- [bzoj2654]tree(最小生成树+二分)
- 【二分+最小生成树】BZOJ2654[tree]题解
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- BZOJ 2654 tree 二分+最小生成树
- [bzoj2654][最小生成树][二分]tree
- BZOJ2654 tree 【二分 + 最小生成树】