码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2654: tree(二分 最小生成树)

时间:2018-05-19 15:40:34      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:||   数据   BMI   swap   etc   while   ace   main   过程   

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 2901  Solved: 1196
[Submit][Status][Discuss]

Description

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

 

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

 

Output

一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

 

 

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2

HINT

 

原数据出错,现已更新 by liutian,但未重测---2016.6.24

 

Source

 

对于图上的最小生成树

如果我们得到的最小生成树上的白边小于$need$条,那么说明白边的权值整体偏大,

那么我们考虑对所有的白边减去一个权值,这样最小生成树上的白边就会变多

这个过程很显然具有单调性,于是可以二分减去的权值

注意一个坑:当权值相同的时候优先选择白边

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1; 
    while(c < 0 || c > 9) {if(c == -) f = -1; c = getchar();}
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar();
    return x * f;
}
int N, M, need;
struct Edge {
    int u, v, w, opt;
    bool operator <(const Edge &rhs) const {
        return w == rhs.w ? opt < rhs.opt : w < rhs.w;
    }
}E[MAXN], e[MAXN];
int Val = 0, fa[MAXN];
int siz[MAXN];
int find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
int unionn(int x, int y) {
    int fx = find(x), fy = find(y);
    if(siz[fx] < siz[fy]) swap(fx, fy);
    fa[fy] = fx;
}
bool check(int x) {
    Val = 0;
    for(int i = 1; i <= M; i++) {
        E[i] = e[i];
        if(e[i].opt == 0) E[i].w += x;
    }
    for(int i = 1; i <= N; i++) 
        fa[i] = i, siz[i] = 1;
    int tot = 0, white = 0;
    sort(E + 1, E + M + 1);
    for(int i = 1; i <= M; i++) {
        if(find(E[i].u) != find(E[i].v)) {
            unionn(E[i].u, E[i].v);
            Val += E[i].w; tot++;
            if(E[i].opt == 0) white++;
        }
        if(tot == N - 1) break;
    }
    return white >= need;
}
main() {
    #ifdef WIN32
    freopen("a.in", "r", stdin);
    #endif
    N = read(), M = read(), need = read();
    for(int i = 1; i <= M; i++) {
        int x = read() + 1, y = read() + 1, z = read(), opt = read();
        e[i] = (Edge){x, y, z, opt};
    }
    int l = -110, r = 110, ans = 0;
    while(l <= r) {
        int mid = l + r >> 1;
        if(check(mid)) ans = Val - mid * need, l = mid + 1;
        else r = mid - 1;    
    } 
    printf("%d", ans);
}

 

BZOJ 2654: tree(二分 最小生成树)

标签:||   数据   BMI   swap   etc   while   ace   main   过程   

原文地址:https://www.cnblogs.com/zwfymqz/p/9060241.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!