[bzoj2654] tree 最小生成树kruskal+二分
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。题目保证有解。
输入格式
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
输出格式
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
样例
样例输入
2 2 1
0 1 1 1
0 1 2 0
样例输出
2
数据范围与提示
原数据出错,现已更新 by liutian,但未重测---2016.6.24
题解:
我们要求一个最小生成树,树中必须恰好包含need条边
在常用的kruskal算法中,一旦边权确定,黑白边就是等价的,但我们要找恰好need条边,所以要让白边尽可能的“特殊”。
想让白边“特殊”,只能给白边改权值。
设用当前的权值求出的最小生成树所含有的白边>need,我们要减少白边数量,就要给每个白边加权值;小于need,要增加白边数量,给白边减权值(加上一个负权)。
那真正的权值怎么求?
我们在kruskal中记录白边个数,白边个数>=need时更新权值:ans=ans-mid×need
一定是白边个数>=need时更新权值,博主在这里卡了半天。
具体原因博主也是看的大佬的题解,现给出解释:
如果在你的二分过程中如果给白边加上mid,你得到的白边数比need大。
给白边加上mid+1,你得到的白边比need小。
这种情况看似没法处理。
但是考虑一下kruskal的加边顺序
可以发现如果出现这种情况,一定是有很多相等的白边和黑边。
因为你排序的时候如果有两条相同权值的黑边和白边,肯定是要把白边排在前面
因为数据保证合法,所以我们可以把一些白边替换成黑边。
所以我们要在白边数>=need的时候更新答案。
那么这个增加的权值如何确定?
二分答案
二分枚举要加上的权值,然后给每个白边加上权值,跑kruskal,出的最小生成树所含有的白边>need,l=mid+1,小于need,r=mid-1。
跑完每遍kruskal后把白边的权值再减回去。
二分结束后,输出当前的实际权值。
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXE 100005
#define MAXV 50005
using namespace std;
int v, e, need;
struct node {
int fr, to, w, col;
friend bool operator < (const node &a, const node &b) {
return (a.w == b.w) ? (a.col < b.col) : (a.w < b.w);
}
} edge[MAXE];
int l = -101, r = 101, mid, ans = 0, res = 0;
int fa[MAXV];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
int kruskal(int mid) {
int sum_edge = 0, sum_white = 0;
res = 0;
for (int i = 1; i <= v; i++) fa[i] = i;
for (int i = 1; i <= e; i++) {
if (!edge[i].col)
edge[i].w += mid;
}
sort(edge + 1, edge + e + 1);
for (int i = 1; i <= e; i++) {
int x = find(edge[i].fr), y = find(edge[i].to);
if (x != y) {
fa[x] = y;
res += edge[i].w;
sum_edge++;
if (!edge[i].col)
sum_white++;
}
if (sum_edge == v - 1)
break;
}
for (int i = 1; i <= e; i++) {
if (!edge[i].col)
edge[i].w -= mid;
}
return sum_white;
}
int main() {
scanf("%d%d%d", &v, &e, &need);
for (int i = 1; i <= e; i++) {
scanf("%d%d%d%d", &edge[i].fr, &edge[i].to, &edge[i].w, &edge[i].col);
edge[i].fr++, edge[i].to++;
}
while (l <= r) {
mid = (l + r) >> 1;
if (kruskal(mid) >= need) {
l = mid + 1;
ans = res - mid * need;
} else
r = mid - 1;
}
printf("%d\n", ans);
return 0;
}
[bzoj2654] tree 最小生成树kruskal+二分的更多相关文章
- [BZOJ2654]:tree(Kruskal+WQS二分)
题目传送门 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树.题目保证有解. 输入格式 开始标号),边权,颜色(0白色1黑色). 输出格式 一行表 ...
- BZOJ2654:tree(最小生成树,二分)
Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色 ...
- [BZOJ2654]tree 最小生成树+贪心
2654: tree Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 2435 Solved: 1011[Submit][Status][Discus ...
- BZOJ2654 tree (wqs二分)
题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 一个最小生成树问题,但是我们要选need条白边,我们用g(i)表示选取i条 ...
- 2021.07.19 BZOJ2654 tree(生成树)
2021.07.19 BZOJ2654 tree(生成树) tree - 黑暗爆炸 2654 - Virtual Judge (vjudge.net) 重点: 1.生成树的本质 2.二分 题意: 有一 ...
- 关于最小生成树 Kruskal 和 Prim 的简述(图论)
模版题为[poj 1287]Networking. 题意我就不说了,我就想简单讲一下Kruskal和Prim算法.卡Kruskal的题似乎几乎为0.(●-`o´-)ノ 假设有一个N个点的连通图,有M条 ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- 最小生成树——Kruskal与Prim算法
最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...
- 【转】最小生成树——Kruskal算法
[转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...
随机推荐
- springboot集成websocket实现向前端浏览器发送一个对象,发送消息操作手动触发
工作中有这样一个需示,我们把项目中用到代码缓存到前端浏览器IndexedDB里面,当系统管理员在后台对代码进行变动操作时我们要更新前端缓存中的代码怎么做开始用想用版本方式来处理,但这样的话每次使用代码 ...
- hadoop高可用HA的配置
zk3 zk4 zk5 配置hadoop的HA大概可以分为以下几步: 配置zookpeer(namenode之间的通信要靠zk来实现) 配置hadoop的 hadoop-env.sh hdfs-sit ...
- Linux课程---14、linux下lamp环境如何安装
Linux课程---14.linux下lamp环境如何安装 一.总结 一句话总结: 要按顺序安装,比如apache需要在php之前安装, 一.安装 gcc 编译器 二.卸载 rpm 安装的 http ...
- 如何在 JavaScript 中使用 C 程序
JavaScript 是个灵活的脚本语言,能方便的处理业务逻辑.当需要传输通信时,我们大多选择 JSON 或 XML 格式. 但在数据长度非常苛刻的情况下,文本协议的效率就非常低了,这时不得不使用二进 ...
- 提问(prompt 消息对话框)用于询问一些需要与用户交互的信息。弹出消息对话框(包含一个确定按钮、取消按钮与一个文本输入框)
提问(prompt 消息对话框) prompt弹出消息对话框,通常用于询问一些需要与用户交互的信息.弹出消息对话框(包含一个确定按钮.取消按钮与一个文本输入框). 语法: prompt(str1, s ...
- docker 个人遇到问题日志记录
system: openSUSE Leap 42.3 在openSUSE中可直接运行" sudo zypper in docker"进行安装docker-ce wakasann@l ...
- 看 《android权威编程指南》 的笔记
Android 编译工具 确保ant已安装并正常运行,android sdk的tools/和platform-tools目录包含在可执行文件的搜索路径中 切换到项目目录并执行以下命令: android ...
- SQFREE - Square-free integers
SQFREE - Square-free integers 求n以内,约数中不包含任意一个平方数的个数,\(n≤10^{14}\). 解 显然为约数计数问题,于是想办法转换为代数问题,不难列出 \[a ...
- 以太坊geth客户端下的一些常用命令
这是一个交互式的 JavaScript 执行环境,在这里面可以执行 JavaScript 代码,其中 > 是命令提示符.在这个环境里也内置了一些用来操作以太坊的 JavaScript 对象,可以 ...
- BCB如何编写,调用动态链接库DLL
一 编写动态链接库DLL DLL简称动态链接库,是Windows中程序的重要组成部分.想象一下,一个程序需要多人共同完成开发,怎么个共同法?这时我们就要考虑把程序分为好几个模块,团队每一个成员开发一个 ...