zoukankan      html  css  js  c++  java
  • bzoj 2654 tree

    题目大意:

    一个无向带权图,每条边为黑或白(1/0)

    求包含k条白边的最小生成树,保证有解

    思路:

    蛇皮题

    高老师提醒了我们二分

    就是二分+mst

    我们二分一个权值,然后对于每个白边加上这个权值

    这样就可以算出我们要取哪些白边

    所以二分的范围要到负数

    如果知道要取哪些白边和黑边,然后直接求出这个树的权值减去白边被加上的值

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<set>
     8 #include<map>
     9 #include<vector>
    10 #include<stack>
    11 #include<queue>
    12 #define ll long long
    13 #define inf 2147383611
    14 #define MAXN 50100
    15 using namespace std;
    16 inline ll read()
    17 {
    18     ll x=0,f=1;
    19     char ch;ch=getchar();
    20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    22     return x*f;
    23 }
    24 int n,m,k;
    25 struct data
    26 {
    27     int from,to,val,col;
    28     bool operator < (const data &a) const
    29     {
    30         return val<a.val;
    31     }
    32 }edge[MAXN*2],tmp[MAXN*2];
    33 int f[MAXN],ans,res;
    34 int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
    35 bool ok(int a,int b)
    36 {
    37     int fa=find(a),fb=find(b);
    38     if(fa==fb) return 1;
    39     else {f[fa]=fb;return 0;}
    40 }
    41 bool check(int x)
    42 {
    43     int cnt=0;res=0,ans=0;
    44     for(int i=1;i<=n;i++) f[i]=i;
    45     for(int i=1;i<=m;i++) {tmp[i]=edge[i];if(!tmp[i].col) tmp[i].val+=x;}
    46     sort(tmp+1,tmp+m+1);
    47     for(int i=1;i<=m;i++)
    48     {
    49         if(!ok(tmp[i].from,tmp[i].to)) {cnt++,ans+=tmp[i].val;if(!tmp[i].col) {res++;ans-=x;}}
    50         if(cnt==n-1) break;
    51         //cout<<x<<" "<<cnt<<" "<<ans<<endl;
    52     }
    53     //cout<<x<<" "<<res<<" "<<ans<<endl;
    54     return res>=k;
    55 }
    56 int main()
    57 {
    58     n=read(),m=read(),k=read();
    59     for(int i=1;i<=m;i++) edge[i].from=read()+1,edge[i].to=read()+1,edge[i].val=read(),edge[i].col=read();
    60     int l=-101,r=101,mid;
    61     while(l<r-1)
    62     {
    63         mid=(l+r)>>1;
    64         if(check(mid)) l=mid;
    65         else r=mid;
    66         if(res==k) break;
    67     }
    68     printf("%d",ans);
    69 }
    View Code
  • 相关阅读:
    基于ObjectCache的应用
    数学趣题——验证角谷猜想
    数学趣题——递归法寻找最小值
    数学趣题——寻找同构数
    数学趣题——表示成两个数的平方和
    数学趣题——马克思手稿中的数学题
    数学趣题——具有特殊性质的数
    数学趣题——验证四方定理
    数学趣题——连续整数固定和问题
    数学趣题——验证尼克彻斯定理
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7717854.html
Copyright © 2011-2022 走看看