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

题目链接: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          }else
77             r=mid-1;
78       }
79       printf("Case %d: %d\n",t++,ans);
80    }
81    return 0;
82 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值