bzoj2654

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
 
特殊处理边权 最小生成树
 
//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=50000+10,maxm=100000+10;
int n,m,nd,fa[maxn],ans;
double k;
 
int aa;char cc;
int read() {
    aa=0;cc=getchar();
    while(cc<'0'||cc>'9') cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    return aa;
}
 
struct Node{
    int x,y,c;double z;
}node[maxm];
 
int find(int x) {
    return x==fa[x]? x:fa[x]=find(fa[x]);
}
 
bool cmp(const Node& a,const Node& b) {
    return a.z+k*a.c<b.z+k*b.c;
}
 
int rs,tot;
int Kr() {
    ans=0;
    int a,b;
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=m;++i) {
        a=find(node[i].x);b=find(node[i].y);
        if(a!=b) {
            fa[a]=b; tot++;
            ans+=node[i].z;
            rs+=node[i].c;
            if(tot==n-1) break;
        }
    }
    return rs;
}
 
int main() {
    n=read();m=read();nd=read();
    for(int i=1;i<=m;++i) {
        node[i].x=read()+1;node[i].y=read()+1;
        node[i].z=read();node[i].c=read()^1;
    }
    sort(node+1,node+m+1,cmp);
    int now;double l=-100,r=100;
    now=Kr();
    while(now!=nd) {
        if(now>nd) l=k+1;else r=k-1;
        k=(l+r)/2.0;
        sort(node+1,node+m+1,cmp);
        now=Kr();
        if(l>=r-0.5) break;
    }
    printf("%d",ans);
    return 0;
}

  

 

 
posted @ 2017-08-27 22:11  shixinyi  阅读(271)  评论(0编辑  收藏  举报