hdu 4253(二分+最小生成树)

来源:互联网 发布:热血传奇闪避命中数据 编辑:程序博客网 时间:2024/06/10 17:59

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4253

思路:求最小生成树是显然的,题目还多了一个限制条件,就是属于A公司的边必须有K条,于是我们可以二分来实现这个目的,找一个尽量大的mid,用A公司的每条边都加上这个mid,使得求出的最小生成树中包含A公司的边至少K条,于是花费ans=sum-K*mid。

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 50000+50 7 #define MAXM 100000+100 8 #define inf 1<<30 9 int parent[MAXN];10 struct Edge{11    int u,v,w;12 }W[MAXM],B[MAXM];13 int n,m,k,sum,cnt,cntw,cntb;14 15 int Find(int x)16 {17    if(x==parent[x])18       return x;19    parent[x]=Find(parent[x]);20    return parent[x];21 }22 23 int cmp(const Edge &p,const Edge &q)24 {25    return p.w<q.w;26 }27 28 bool Union(int u,int v)29 {30    int r1=Find(u),r2=Find(v);31    if(r1==r2)return false;32    parent[r1]=r2;33    return true;34 }35 36 bool Judge(int w)37 {38    for(int i=0;i<=n;i++)39       parent[i]=i;40    cnt=sum=0;41    int la=0,lb=0;42    while(la<cntw||lb<cntb){43       if(W[la].w+w<=B[lb].w){44          if(Union(W[la].u,W[la].v)){ sum+=W[la].w+w;cnt++; }45          la++;46       }else{47          if(Union(B[lb].u,B[lb].v))sum+=B[lb].w;48          lb++;49       }50    }51    if(cnt>=k)return true;52    return false;53 }54 55 56 int main()57 {58   // freopen("1.txt","r",stdin);59    int u,v,w,tag,ans,t=1;60    while(~scanf("%d%d%d",&n,&m,&k)){61       cntw=cntb=0;62       while(m--){63          scanf("%d%d%d%d",&u,&v,&w,&tag);64          if(tag){ B[cntb].u=u,B[cntb].v=v,B[cntb++].w=w; }65          else { W[cntw].u=u,W[cntw].v=v,W[cntw++].w=w; }66       }67       sort(B,B+cntb,cmp);68       sort(W,W+cntw,cmp);69       B[cntb].w=W[cntw].w=inf;70       int l=-100,r=100,mid;71       while(l<=r){72          mid=(l+r)>>1;73          if(Judge(mid)){74             ans=sum-mid*k;75             l=mid+1;76          }else77             r=mid-1;78       }79       printf("Case %d: %d\n",t++,ans);80    }81    return 0;82 }
View Code

 

0 0
原创粉丝点击