【二分+最小生成树】BZOJ2654[tree]题解
2017-10-30 14:24
399 查看
题目概述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有 K 条白色边的生成树。解题报告
可怕的题目……首先我们可以先求出一棵最小生成树,但是不一定满足 K 条白色边。这怎么办呢?容易想到提高(降低)白色边的优先级,从而多选(少选)白色边。
于是我们可以将白色边的边权全加上 mid (这样白色边之间的优先级保持不变),然后重新求最小生成树,如果满足要求说明 mid 可行。而由于 mid 对白色边的影响是单调的,所以可以二分。
还需要注意,Kruskal对边排序时,应该双关键字排序(白色边比边权相同的黑色边优先)。
示例程序
#include<cstdio> #include<algorithm> #define fr first #define sc second using namespace std; typedef pair< pair<int,int>,pair<int,int> > Edge; const int maxn=50000,maxe=100000; int n,m,K;Edge e[maxe+5]; int father[maxn+5],now,ans; #define val(e) (e.sc.fr+now*(e.sc.sc^1)) inline bool cmp(Edge a,Edge b) {return val(a)<val(b)||val(a)==val(b)&&a.sc.sc<b.sc.sc;} int getfa(int x) {if (father[x]==x) return x;return father[x]=getfa(father[x]);} inline bool check(int mid) { int tot=0;ans=0;now=mid;for (int i=0;i<n;i++) father[i]=i;sort(e+1,e+1+m,cmp); for (int i=1;i<=m;i++) { int fx=getfa(e[i].fr.fr),fy=getfa(e[i].fr.sc);if (fx==fy) continue; ans+=val(e[i]);tot+=!e[i].sc.sc;father[fx]=fy; } return tot>=K; } int main() { freopen("program.in","r",stdin); freopen("program.out","w",stdout); scanf("%d%d%d",&n,&m,&K); for (int i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].fr.fr,&e[i].fr.sc,&e[i].sc.fr,&e[i].sc.sc); int L=-105,R=105; for (int mid=L+(R-L>>1);L<=R;mid=L+(R-L>>1)) if (check(mid)) L=mid+1; else R=mid-1; return check(R),printf("%d\n",ans-R*K),0; }
相关文章推荐
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- bzoj 2654: tree (二分+最小生成树)
- 【bzoj2654】【tree】【二分+最小生成树】
- 【BZOJ2654】tree【二分】【最小生成树】
- 【BZOJ2654】tree 二分+最小生成树
- BZOJ 2654 tree(二分答案+最小生成树)
- bzoj 2654 tree (二分 + 最小生成树)
- [bzoj2654]tree(最小生成树+二分)
- 【bzoj2654】【二分+最小生成树】tree
- [bzoj2654]tree(二分+最小生成树)
- BZOJ 2654 tree 二分+最小生成树
- [bzoj2654][最小生成树][二分]tree
- bzoj2654: tree(二分+最小生成树)
- [bzoj2654]tree 二分+最小生成树
- 【二分+最小生成树】bzoj2654 tree
- BZOJ2654 tree 【二分 + 最小生成树】
- BZOJ 2654: tree 最小生成树+二分
- 二分+最小生成树【bzoj2654】: tree
- bzoj 2654: tree 二分+最小生成树
- 【二分+最小生成树】BZOJ2654 tree