【bzoj1196】 公路修建 二分+最大生成树

    “花费最多的一条公路的花费尽可能的少”一句话是二分的标志。我们二分花费最多的公路的花费x,然后对于每一条路:如果修建一级公路的费用不大于x,那么就连一条权值为1的边;如果修建二级公路的费用不大于x,就连一条权值为0的边;如果都不能修,就不连边。由于题目中要求所有城市连在一起,而且一级公路要尽可能多,所以我们就跑一遍最大生成树。跑完后,如果发现连不起来或者一级公路的条数小于k,就说明不可行;反之说明可行。

下附AC代码:

#include <cstdio>
#include <cstring>
#define N 12000 
#define M 30000 
using namespace std;
 
int x[M],y[M],u[M],v[M],u_[M],v_[M],c1[M],c2[M],n,k,m,fa[N];
int getfa(int xx){
    if (fa[xx]==xx) return xx;
    return fa[xx]=getfa(fa[xx]);
}
int ok(int num){
    int sum=0,tot1=0,tot2=0,i;
    for (i=1; i<m; i++)
        if (c1[i]<=num){ tot1++; u[tot1]=x[i]; v[tot1]=y[i];} else
        if (c2[i]<=num){ tot2++; u_[tot2]=x[i]; v_[tot2]=y[i]; }
    for (i=1; i<=n; i++) fa[i]=i;
    int p,q;
    for (i=1; i<=tot1; i++){
        p=getfa(u[i]); q=getfa(v[i]);
        if (p!=q){ sum++; fa[p]=q; }
    }
    if (sum<k) return 0;
    for (i=1; i<=tot2; i++){
        p=getfa(u_[i]); q=getfa(v_[i]);
        if (p!=q) fa[p]=q;
    }
    for (i=2; i<=n; i++)
        if (getfa(fa[i])!=getfa(fa[1])) return 0;
    return 1;
}
int main(){
    scanf("%d%d%d",&n,&k,&m);
    int i;
    for (i=1; i<m; i++)
        scanf("%d%d%d%d",&x[i],&y[i],&c1[i],&c2[i]);
    int r,l,mid;
    r=1; l=30000;
    while (r+1<l){
        mid=(r+l)/2;
        if (ok(mid)) l=mid; else r=mid+1;
    }
    if (ok(r)) printf("%d",r); else printf("%d",l);
    return 0;
}


2015.2.20

by lych

你可能感兴趣的:(最小生成树,二分)