您的位置:首页 > 其它

[bzoj2654]tree 二分+最小生成树

2017-07-04 21:34 465 查看

2654: tree

Time Limit: 30 Sec  Memory Limit: 512 MB

[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

就二分再kruskal一下就完了。没做头
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 100005;
struct Edge{
int u,v,w,c;
}e
;
int a
,u
,v
,w
,c
,fa
,n,m,maxn,ans,scnt,cnt,need;
int find( int x ){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
bool cmp( Edge a, Edge b ){ return a.w == b.w ? a.c < b.c : a.w < b.w; }
bool check( int x ){
scnt = cnt = 0;
for( int i = 1; i <= n; i++ ) fa[i] = i;
for( int i = 1; i <= m; i++ ){
e[i].u = u[i]; e[i].v = v[i];
e[i].w = w[i]; e[i].c = c[i];
if( !c[i] ) e[i].w += x;
}
std::sort( e+1, e+m+1, cmp );
for( int i = 1; i <= m; i++ ){
int A = find(e[i].u), B = find(e[i].v);
if( A != B ){
fa[A] = fa[B]; if(!e[i].c) scnt++;
cnt += e[i].w;
}
}
return scnt >= need;
}
int main(){
scanf("%d", &n); scanf("%d", &m); scanf("%d", &need);
for( int i = 1; i <= m; i++ ) scanf("%d%d%d%d", &u[i], &v[i], &w[i], &c[i]),u[i]++,v[i]++;
int l = -105, r = 105;
while( l <= r ){
int mid = (l+r)>>1;
if( check(mid) ) l = mid+1, ans = cnt-need*mid;
else r = mid-1;
}
printf("%d", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: