最小生成树 tree(陈立杰)

问题 D: tree
时间限制: 3 Sec 内存限制: 512 MB
提交: 24 解决: 7
[提交][状态][讨论版]
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有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
因为当前最小生成树上的白边是不确定的,所以通过修改白边的优先级来改变生成树上白边的数量。那么怎么修改呢?改边权。当然就想到二分答案了,给白边加上当前二分的值(-100,100)如果白边过多,加大值,过少反之。
注意,会有很多边边权一样,这时,白边数量q>k也可以是成立的(只要把一些等权的白边改成黑边就行了)注意最后答案要减去need*mid(二分的值)

     #include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,k,mid,e,ans,q,adj[50005],f[50005];
struct road
{
    int u,v,next,l,h;
    bool friend operator <(road a,road b)
    {
        return a.l!=b.l ? a.l<b.l : a.h<b.h;
    }
}lu[100005];
void add(int u,int v,int l,int h)
{lu[++e].u=u;lu[e].h=h;lu[e].v=v;lu[e].l=l;lu[e].next=adj[u];adj[u]=e;}
inline int find(int x){return f[x]==x ? x:f[x]=find(f[x]);}
inline void hb(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy)f[fx]=fy;}
inline int read()
{
    int sum=0,f=1;char x=getchar();
    while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
    while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
    return sum*f;
}
int check()
{
    ans=0;q=0;int w=0;
    for(int i=1;i<=m;i++)if(!lu[i].h)lu[i].l+=mid;
    sort(lu+1,lu+m+1);
    for(int i=0;i<n;i++)f[i]=i;
    for(int i=1;i<=m;i++)
    {
        if(find(lu[i].u)!=find(lu[i].v))
        {
            w++;
            hb(lu[i].u,lu[i].v);
            ans+=lu[i].l;
            if(!lu[i].h)q+=1;
        }
        if(w==n-1)break;
    }
    for(int i=1;i<=m;i++)if(!lu[i].h)lu[i].l-=mid;
    //cout<<q<<" "<<ans<<endl;
    if(q>=k)return 1;
    return 0;
}
int yjn()
{
//  freopen("nt2012_tree.in","r",stdin);
//  freopen("nt2012_tree.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    int x,y,z,h;
    for(int i=1;i<=m;i++)
    {
        x=read();y=read();z=read();h=read();
        add(x,y,z,h);
    }
    int l=-100,r=100,w=0;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(check())
      {
           l=mid+1,w=ans-k*mid;
       }
       else r=mid-1;
   }
    cout<<w;
}
int qty=yjn();
int main(){;}
posted @ 2017-10-06 20:19  Hzoi_QTY  阅读(211)  评论(0编辑  收藏  举报