[bzoj2654][最小生成树][二分]tree
2017-12-14 14:01
393 查看
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
题解
神题呐不会啊只能膜题解了。。
如果直接对原树进行kruskal的话,求出来的白边可能<need也可能>need的对不
那么怎么人为控制白边在树里的数目同时保证黑边选择最小呐?
还是最小生成树,只不过我们二分一个值mid,每次check的时候每条白边加上这个mid值,这样可以保证白边在生成树里一定是单调不下降或者单调不上升的,而这个时候的黑边同样有保证一定是最小的。
跑kruskal的时候判一下白边的边数,如果出来的边数>=need就是正确状态,那么树里的白边就需要减小,这时候mid往大的二分
小于need的情况就往小的二分
答案继承的时候需要减去mid*need这么多,因为白边至少都多了这么多的权嘛
一个特别的地方:题里可能有权相等的黑白边,这样kruskal排序的时候黑白边顺序是不定的。那这样跑出来的边数就可能小于need而wa掉。所以我们排序的时候当边权相等的时候再按颜色排,白色在前
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有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
题解
神题呐不会啊只能膜题解了。。
如果直接对原树进行kruskal的话,求出来的白边可能<need也可能>need的对不
那么怎么人为控制白边在树里的数目同时保证黑边选择最小呐?
还是最小生成树,只不过我们二分一个值mid,每次check的时候每条白边加上这个mid值,这样可以保证白边在生成树里一定是单调不下降或者单调不上升的,而这个时候的黑边同样有保证一定是最小的。
跑kruskal的时候判一下白边的边数,如果出来的边数>=need就是正确状态,那么树里的白边就需要减小,这时候mid往大的二分
小于need的情况就往小的二分
答案继承的时候需要减去mid*need这么多,因为白边至少都多了这么多的权嘛
一个特别的地方:题里可能有权相等的黑白边,这样kruskal排序的时候黑白边顺序是不定的。那这样跑出来的边数就可能小于need而wa掉。所以我们排序的时候当边权相等的时候再按颜色排,白色在前
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,c,op; }a[211000],e[211000]; int fa[111000]; int findfa(int x) { if(fa[x]!=x)fa[x]=findfa(fa[x]); return fa[x]; } int n,m,nd,cnt; bool cmp(node n1,node n2) { if(n1.c!=n2.c)return n1.c<n2.c; else return n1.op<n2.op; } bool chk(int p) { for(int i=1;i<=m;i++) { e[i]=a[i]; if(a[i].op==0)e[i].c+=p; } for(int i=1;i<=n;i++)fa[i]=i; sort(e+1,e+1+m,cmp); int tmp=n,op=0;cnt=0; for(int i=1;i<=m;i++) { int p=findfa(e[i].x),q=findfa(e[i].y); if(p!=q) { fa[p]=q; cnt+=e[i].c;tmp--; if(e[i].op==0)op++; if(tmp==1)break; } } if(op>=nd)return true; else return false; } int main() { scanf("%d%d%d",&n,&m,&nd); for(int i=1;i<=m;i++){scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].c,&a[i].op);a[i].x++;a[i].y++;} int l=-150,r=150,ans; while(l<=r) { int mid=(l+r)/2; if(chk(mid)) { ans=cnt-nd*mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); return 0; }
相关文章推荐
- [bzoj2654]tree(二分+最小生成树)
- 【二分+最小生成树】BZOJ2654[tree]题解
- [bzoj2654]tree(最小生成树+二分)
- BZOJ 2654: tree 最小生成树+二分
- [bzoj2654]tree 二分+最小生成树
- bzoj 2654: tree (二分+最小生成树)
- 【二分+最小生成树】BZOJ2654 tree
- BZOJ 2654 tree 二分+最小生成树
- bzoj2654: tree(二分+最小生成树)
- BZOJ 2654 tree - 二分+最小生成树
- 【二分+最小生成树】bzoj2654 tree
- 【BZOJ2654】tree 二分+最小生成树
- bzoj 2654: tree 二分+最小生成树
- 二分+最小生成树【bzoj2654】: tree
- BZOJ2654 tree 【二分 + 最小生成树】
- 【bzoj2654】【tree】【二分+最小生成树】
- bzoj 2654 tree (二分 + 最小生成树)
- BZOJ 2654 tree(二分答案+最小生成树)
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- 【BZOJ2654】tree【二分】【最小生成树】