BZOJ 2654浅谈二分+最小生成树推导
来源:互联网 发布:java字符串拼接空格 编辑:程序博客网 时间:2024/06/11 04:20
世界真的很大
今天的风儿甚是喧嚣,豆大的雨滴悄咪咪地往下落
这也是一道挺有意思的题
难点在于推导,并不在于代码
主要是锻炼对模板的熟悉程度,和思维难度
但只是马马虎虎地靠感觉推导其实也并没有那么困难
只是认真想来有一点细思恐极的味道
还是看一下题为好
description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。题目保证有解。
input
第一行V,E,need分别表示点数,边数和需要的白色边数。接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
output
一行表示所求生成树的边权和。V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
读完题就该想到最小生成树了
但关键是怎么把握白色边的个数
Kruscal算法的基本原理是边按权值排序,从小往大凑满n-1条边
如果我们能让白色边的排序稍微靠后,那取到白色边的可能就会降低,起码白色边的数量会小于等于之前的数量
让白色边的排序靠后的办法,无非也是给所有的白色边增加权值了
因为随增加权值的增加,白色边的数量单调递减,所以具有可二分的性质
于是乎我们采用二分的办法来逐渐逼近need值,算出那时的最小生成树的权值和
姑且看来就是这样了,代码也很好写
但还有点点
假设有一串增加的权值,使得白色边的数量都是need,那它们所对应的最小生成树的值是相等的吗?
现在我和大佬讨论后,有两种学说
1。是相等的。因为在增加的权值增加时,边排序里,白色边的相对位置肯定是向后挪的。如果使最小生成树的结构不同的话,必然有不属于之前的最小生成树的边加入,也就是说白色边增加权值后大于了新的边,使其相对位置提前。而由于白色边自己的相对位置是不变的,所以提前的只能是黑色边。这条新的黑色边不属于之前的最小生成树,即白色边向后挪的过程中超出了之前的最小生成树的n-1条边,那白色边的数量必然减少,而白色边的数量不变,所以矛盾,所以就是最小生成树的结构不变。
2。随着增加的权值的增加,白色边数量不变的情况下,最小生成树的权值是递增的。因为如果结构改变,使得一条白色边取不到的话,就必然有一条边来替代它的位置,白色边的相对位置不变,所以只能是黑色边。而白色边的数量不变,所以末尾必然有一条白色边补充。白色边的相对位置不变,所以后面补充的白色边的权值一定大于之前白色边的权值。所以是递增的、
这个嘛,两边都有道理,不管是哪边正确,只需要在二分的时候尽可能往左边靠就行了,保证取到need值的是增加的权值最少的点
完整代码:
#include<stdio.h>#include<algorithm>using namespace std;struct edge{ int u,v,w,clr;}ed[500010];int n,m,ned,sum=0,ans,fa[500010];bool cmp(const edge &a,const edge &b){ return a.w<b.w;}int getfather(int x){ if(x==fa[x]) return x; return fa[x]=getfather(fa[x]);}int Kruscal(int x){ int bns=0,tot=0;sum=0; for(int i=0;i<n;i++) fa[i]=i; sort(ed+1,ed+m+1,cmp); for(int i=1;i<=m;i++) { int x=getfather(ed[i].u); int y=getfather(ed[i].v); if(x!=y) { tot++; fa[x]=y; sum+=ed[i].w; if(!ed[i].clr) bns++; } if(tot==n-1) break ; } sum-=x*bns; for(int i=1;i<=m;i++) if(!ed[i].clr) ed[i].w-=x; return bns;}int check(int x){ for(int i=1;i<=m;i++) if(!ed[i].clr) ed[i].w+=x; return Kruscal(x);}int main(){ scanf("%d%d%d",&n,&m,&ned); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w,&ed[i].clr); int lf=-10000,rg=10000; while(lf<=rg) { int mid=(lf+rg)>>1; int tmp=check(mid); if(tmp>=ned) { ans=sum; lf=mid+1; } else rg=mid-1; } printf("%d",ans); return 0;}
嗯,就是这样
- BZOJ 2654浅谈二分+最小生成树推导
- BZOJ 2654 tree 二分+最小生成树
- bzoj 2654: tree 二分+最小生成树
- BZOJ 2654 二分+最小生成树
- BZOJ 2654: tree 最小生成树+二分
- bzoj 2654: tree (二分+最小生成树)
- BZOJ 2654 tree 详解(最小生成树 kruskal 二分)
- bzoj 2654 tree (二分 + 最小生成树)
- BZOJ 2654 tree(二分答案+最小生成树)
- BZOJ 2561 浅谈最小生成树最小割
- <考试题> bzoj 1821 部落划分 (二分、最小生成树)
- 二分+最小生成树
- 浅谈最小生成树
- BZOJ-2654 贪心 最小生成树
- bzoj 2561: 最小生成树
- BZOJ 1050 最小生成树
- bzoj 1232 最小生成树
- bzoj 2561: 最小生成树
- 在Linux安装配置Tomcat 并部署web应用 ( 三种方式 )
- 友元函数 friend
- 常用邮件协议
- CJOJ 1943 【重庆八中模拟赛】寻找代表元
- 神奇的 LitePal 操作数据库(一)
- BZOJ 2654浅谈二分+最小生成树推导
- linux,postgresql下载
- Unity3D
- PCM数据格式
- Eclipse 导入项目报错解决办法
- forward和redirect的区别
- 简易手动部署多节点的Openstack(L版)——叁(安装Glance服务)
- Git的思想和基本工作原理
- 学习笔记2017.07.06-day4,am2-HTML布局