hdu4253 Two Famous Companies --- 二分+MST

来源:互联网 发布:ubuntu设置ip地址命令 编辑:程序博客网 时间:2024/05/22 09:24

给n个点,m条边的图,每条边要么属于a公司,要么属于b公司。要求一颗最小生成树,条件是其中属于a公司的边数为k。


这题做法很巧妙。

要求最小生成树,但有一定限制,搜索、贪心显然都不对。

要是能找到一种合理的控制方法,使得求MST的过程中可以控制a公司边的数量,那样问题就解决了。

所以我们可以人为给a公司的边加上一定的权值,使得其中一些边不得不退出MST的选择范围内。

如果此时求的mst里a公司的边数>k,那么就要增加权值;边数<k时,权值为负。

所以,通过二分边权值,可以使得求得mst里所含a公司的边数逐渐逼近k,此时记录答案,因为一定有解,所以最终一定是所求答案。


#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;const int maxm=100010;const int maxn=50010;struct node{    int u,v,w,ty;}e[maxm];int r[maxn],n,m,k,ret,telecom;bool cmpw(node a,node b){    if(a.w!=b.w) return a.w<b.w;    return a.ty<b.ty;}int root(int a){    if(r[a]==-1) return a;    return r[a]=root(r[a]);}bool kru(int x){    for(int i=0;i<m;i++)        if(e[i].ty==0) e[i].w+=x;    sort(e,e+m,cmpw);    memset(r,-1,sizeof r);    int edge=0;telecom=n-1;ret=0;    for(int i=0;i<m;i++)    {        int ra=root(e[i].u);        int rb=root(e[i].v);        if(ra!=rb)        {            r[ra]=rb;            ret+=e[i].w;            telecom-=e[i].ty;            if(++edge==n-1) break;        }    }    for(int i=0;i<m;i++)        if(e[i].ty==0) e[i].w-=x;    return telecom>=k;}int main(){    int cas=1;    while(~scanf("%d%d%d",&n,&m,&k))    {        for(int i=0;i<m;i++)            scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w,&e[i].ty);        int l=-100,r=100,mid,ans=0x3f3f3f3f;        while(l<=r)        {            mid=(l+r)/2;            if(kru(mid)) l=mid+1,ans=ret-mid*k;            else r=mid-1;        }        printf("Case %d: %d\n",cas++,ans);    }    return 0;}


0 0
原创粉丝点击