题目描述

原题来自:2012 年国家集训队互测

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有 条白色边的生成树。题目保证有解。

输入格式

第一行V,E,need 分别表示点数,边数和需要的白色边数。

接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色,1黑色)。

输出格式

一行表示所求生成树的边权和。

样例

样例输入

2 2 1
0 1 1 1
0 1 2 0

样例输出

2

题解:

这个题要求在选取特定数量的基础上,构造一棵最小生成树。我们想一下,因为最小生成树所选择的是当前排序后最小的边(采用克鲁斯卡尔算法),如果我们把白色的边增大,那么这棵最小生成树里面的白色边就会少一些(因为边越大,排序的次序就越靠后),反之亦然。那么我们跑一个二分,把所有白边减一个mid,如果在此时最小生成树的白边数量比题目要求大,就说明目前mid的值大了,将其减少,否则将其增大。当此时最小生成树的白边数量等于题目所给的need时,说明此时的最小生成树即使满足题目要求的最佳情况,且因为此时最小生成树的值是在所有白边都减了一个mid的基础之上,所以答案还需增加一个need*mid;
有一位大佬问了我一个问题:

个人认为你并没有说明可以一定可以取到一个值使得恰好为k个

那么下面附上我的回答(感谢这位大佬!!!)

因为mid的值是没有范围的,所以我们可以通过mid的大小让所有的白边比最小的黑边还小,或者让他们比最大的黑边还大,那么在确保黑边有n-1条后,我们可以让白边的数量通过mid确定范围为0~n-1,所以一定有一个值使得恰好为k个(只要黑边数量大于n-1)

代码

#include<bits/stdc++.h>
using namespace std; struct zz{
int u,v,w,col;
}a[100005]; int pre[50005];
int n,m,k; int Find(int x){
if(pre[x]!=x){
pre[x]=Find(pre[x]);
}
return pre[x];
} bool cmp(zz x,zz y){
if(x.w!=y.w)
return x.w<y.w;
return x.col<y.col; //如果两个值相同,白色放前面(或者说是优先考虑白色),如果不相同,那么根据克鲁斯卡尔,权值小的放前面;
} int CHEAK(int pd,int mid){ //克鲁斯卡尔,如果pd为一,那么说明 我们在统计最小生成树的权值和,如果等于0,那么说明我们在判断白边的个数;
for(int i=1;i<=m;i++){
if(a[i].col==0){
a[i].w-=mid; //全部减去mid;
}
}
for(int i=0;i<n;i++)
pre[i]=i;
sort(a+1,a+m+1,cmp);
int cnt=0,toto=0,sum=0;
for(int i=1;i<=m;i++){
int fx=Find(a[i].u),fy=Find(a[i].v);
if(fx==fy)
continue;
pre[fx]=fy;
sum+=a[i].w;
if(a[i].col==0)
cnt++; //如果是白边,则统计;
toto++;
if(toto==n-1) break;
}
for(int i=1;i<=m;i++){
if(a[i].col==0)
a[i].w+=mid; //减了之后别忘加回来!!!
}
if(pd==0)
return cnt;
return sum;
} int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].w,&a[i].col);
}
int l=-105,r=105; //二分边界
int ans=105; //统计最后减去的mid;
while(l<=r){
int mid=(l+r)/2;
int pd=CHEAK(0,mid);
if(pd>=k)
r=mid-1,ans=mid;
else
l=mid+1;
}
cout<<CHEAK(1,ans)+k*ans; //答案记得加上减去的mid;
}

最新文章

  1. OpenGL学习笔记0——安装库
  2. qau-国庆七天乐——B
  3. HDU 2795 Billboard(线段树)
  4. nyoj1007(euler 函数)
  5. Redis客户端之Spring整合Jedis
  6. js中State模式的解析及运用
  7. svn 中commit时必须填写备注信息如何设置
  8. CSS——京东首页实战总结
  9. php 5.0 与7.0有什么区别
  10. HRBUST1522【单调队列+DP】
  11. Excel 统计区间频数,按照条件标记
  12. SELinux入门简介
  13. js匹配字符串
  14. IntelliJ IDEA插件 - ApiDebugger
  15. python __setattr__、__getattr__、__getattribute__全面详解
  16. Maven安装Oracle驱动包到本地仓库
  17. 【3-30】document获取、事件、标记样式
  18. 建立一个php 基础类
  19. 一分钟了解Android横竖屏 mdpi hdpi xhdpi xxhdpi xxxhdpi (转)
  20. Linux init 0-6 启动级别

热门文章

  1. WIKI和JIRA-安装与使用
  2. Python基础之变量、输入、输出
  3. GPIO模式用法
  4. 『言善信』Fiddler工具 — 2、HTTP请求内容详解
  5. 在ssm框架测试中解决javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException
  6. 如何让Android 支持HEIF 图片解码和加载(免费的方法)
  7. [LeetCode] 1074. 元素和为目标值的子矩阵数量
  8. Python+Selenium自动化-定位一组元素,单选框、复选框的选中方法
  9. Django学习之完成数据库主从复制、读写分离和一主多从情况下的使用办法
  10. TheSuperego 实验五 团队作业2:毕业设计选题系统