题目描述

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有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+二分的更多相关文章

  1. [BZOJ2654]:tree(Kruskal+WQS二分)

    题目传送门 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树.题目保证有解. 输入格式 开始标号),边权,颜色(0白色1黑色). 输出格式 一行表 ...

  2. BZOJ2654:tree(最小生成树,二分)

    Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色 ...

  3. [BZOJ2654]tree 最小生成树+贪心

    2654: tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 2435  Solved: 1011[Submit][Status][Discus ...

  4. BZOJ2654 tree (wqs二分)

    题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解.   一个最小生成树问题,但是我们要选need条白边,我们用g(i)表示选取i条 ...

  5. 2021.07.19 BZOJ2654 tree(生成树)

    2021.07.19 BZOJ2654 tree(生成树) tree - 黑暗爆炸 2654 - Virtual Judge (vjudge.net) 重点: 1.生成树的本质 2.二分 题意: 有一 ...

  6. 关于最小生成树 Kruskal 和 Prim 的简述(图论)

    模版题为[poj 1287]Networking. 题意我就不说了,我就想简单讲一下Kruskal和Prim算法.卡Kruskal的题似乎几乎为0.(●-`o´-)ノ 假设有一个N个点的连通图,有M条 ...

  7. 模板——最小生成树kruskal算法+并查集数据结构

    并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...

  8. 最小生成树——Kruskal与Prim算法

    最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...

  9. 【转】最小生成树——Kruskal算法

    [转]最小生成树--Kruskal算法 标签(空格分隔): 算法 本文是转载,原文在最小生成树-Prim算法和Kruskal算法,因为复试的时候只用到Kruskal算法即可,故这里不再涉及Prim算法 ...

随机推荐

  1. NPM一Node包管理和分发工具

    NPM 全称 Node Package Manager Node包管理和分发工具,可以把NPM理解为前端的Maven 我们通过npm可以很方便地下载js库,管理前端工程 最近版本的node.js已经集 ...

  2. day29 面向对象入门

    Python之路,Day17 = Python基础17-面向对象入门 创建类和对象 面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “ ...

  3. thinkphp 自动加载

    在3.2中,基本上无需手动加载类库文件,你可以很方便的完成自动加载. 命名空间自动加载 系统可以通过类的命名空间自动定位到类库文件,例如: 我们定义了一个类 Org\Util\Auth 类: name ...

  4. linux中对EINTR错误的处理

    https://www.cnblogs.com/flyfish10000/articles/2576885.html EINTR错误的产生:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函 ...

  5. duilib库分析4.第二篇UIBase

    DUiLib 源码分析 ——以UiLib 1.01版为分析目标 ——colin3dmax 分析于2011-6-16 19:44------------------------------------- ...

  6. Android NDK应用原理

    转:http://shihongzhi.com/ndk/ 那么首先看一下Android的系统框架: 最底层是Linux Kernel,然后上面是封装的库及Android runtime.再上面是App ...

  7. com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"

    报错: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected estab ...

  8. 解决方案 -SQL脚本建表产生ORA-00942错误

    一.问题简介 1.开发环境 操作系统:win10 数 据 库:Oracle11g 数据库连接工具:Navicat  Premium 2.问题简述 在使用SQL Development.Navicat  ...

  9. zookeeper 选举白话理解

  10. 5.1_Spring Boot2.x安装Docker

    1.简介 Docker是一个开源的应用容器引擎:是一个轻量级容器技术: Docker 是一个开源的应用容器引擎,基于Go 语言并遵从Apache2.0协议开源.Docker 可以让开发者打包他们的应用 ...