• [HNOI2006] 公路修建问题


    公路修建问题

    题目描述

    输入输出格式

    输入格式:

    在实际评测时,将只会有m-1行公路

    输出格式:

    输入输出样例

    输入样例#1:

    4 2 5
    1 2 6 5
    1 3 3 1
    2 3 9 4
    2 4 6 1

    输出样例#1:

    6
    1 1
    2 1
    4 1

    题解

    看到要求路径中花费最大的一条边花费最小,最小值最大?马上二分
    二分什么?二分出一个最大花费,只有小于等于这个花费的边才加进来,那么怎么验证?
    二分出的这个花费依然要保证这个图联通,也就是一棵树
    我们可以使用并查集,维护集合的连通性
    两次for循环,第一次只选一级公路,并统计个数
    第二次只选二级公路
    最后判断所选一级公路的条数是不是大于等于题目所给的k值,除此之外还要判断图是否联通,为什么?,因为到后面二分值越来越小,选的边越来越少,不一定保证图联通,所以最后我们还要判断一下边的条数是不是等于n-1
    这道题还可以用最小生成树做,个人感觉麻烦一些

    #include<bits/stdc++.h>
    #define in(i) (i=read())
    using namespace std;
    int read() {
      int ans=0,f=1; char i=getchar();
      while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
      while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
      return ans*f;
    }
    struct node {
        int x,y,v,w;
    }a[20010];
    struct tq {
        int id,p;
    }ans[20010],as[20010];
    int n,k,m,l,r=30010,tot,sum;
    int fa[10010];
    int find(int x) {
        if(fa[x]!=x) fa[x]=find(fa[x]);
        return fa[x];
    }
    bool check(int mid) {
        int cnt=0;
        for(int i=1;i<=m;++i) {
            if(a[i].v<=mid) {
                int fx=find(a[i].x),fy=find(a[i].y);
                if(fx!=fy) fa[fx]=fy,cnt++,ans[++tot].id=i,ans[tot].p=1;
            }
        }
        for(int i=1;i<=m;++i) {
            if(a[i].v>mid && a[i].w<=mid) {
                int fx=find(a[i].x),fy=find(a[i].y);
                if(fx!=fy) fa[fx]=fy,ans[++tot].id=i,ans[tot].p=2;
            }
        }
        return ((cnt>=k)&&tot==n-1);
    }
    int main()
    {
        in(n);in(k);in(m);--m;
        for(int i=1;i<=m;++i) in(a[i].x),in(a[i].y),in(a[i].v),in(a[i].w);
        while(l<r) {
            for(int i=1;i<=n;i++) fa[i]=i;
            int mid=l+r>>1;tot=0;
            if(check(mid)) {
                r=mid; sum=tot;
                for(int i=1;i<=sum;++i)
                    as[i].id=ans[i].id,as[i].p=ans[i].p;
            }
            else l=mid+1;
        }
        printf("%d
    ",r);
        for(int i=1;i<=sum;++i) printf("%d %d
    ",as[i].id,as[i].p);
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    My SQL
    弹窗
    DBDA
    ThinkPHP验证码与文件上传
    ThinkPHP表单验证
    ThinkPHP增删改
    ThinkPHP模型(查询)
    ThinkPHP跨控制器调用方法
    Superset安装
    Presto资源组配置
  • 原文地址:https://www.cnblogs.com/real-l/p/9492826.html
Copyright © 2020-2023  润新知