zoukankan      html  css  js  c++  java
  • [ HNOI 2006 ] 公路修建问题

    (\)

    (Description)


    一个(N)个点(M)条边的图,每条边可以选择(w_i,p_i)两个边权之一,现求一个生成树上的最大边权最小值,要求这棵生成树上至少有(K)条边选择的是(w_i)权值。(Luogu)上还要以"选了哪些编号的边,每条边选择的是哪种权值"的形式求输出方案。

    • (Nin [1,10^4])(Min [0,2 imes 10^4])(Kin [0,N-1])(w_i,p_iin [1,3 imes 10^4])

    (\)

    (Solution)


    • 最小生成树变形。先将边按照(w_i)排序,按照(kruskal)的方式连上(K)条边,再按照(min(w_i,p_i))排序,连完剩下的所有边,注意第一遍连上的边要打上标记,避免使用了两次。答案即为所有连过的边中边权最大值,还要注意处理(K=0)(K=N-1)的两种情况。
    • 关于输出方案,每次记录一下就好,注意第二遍扫描的时候也可能取第一类权值。

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 10010
    #define M 20010
    #define R register
    #define gc getchar
    using namespace std;
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int n,m,k,cnt,res,tot;
    
    struct edge{int x,y,w1,w2,num;}e[M];
    
    struct result{int p,x;}ans[N];
    
    inline bool cmp1(edge x,edge y){return x.w1<y.w1;}
    
    inline bool cmp2(edge x,edge y){return min(x.w1,x.w2)<min(y.w1,y.w2);}
    
    inline bool cmp3(result x,result y){return x.p<y.p;}
    
    struct UFS{
      int f[N];
      UFS(){for(R int i=1;i<N;++i) f[i]=i;}
      int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
      inline void merge(int x,int y){f[find(x)]=find(y);}
      inline bool judge(int x,int y){return find(x)==find(y);}
    }ufs;
    
    int main(){
      n=rd(); k=rd(); m=rd()-1;
      for(R int i=1;i<=m;++i){
        e[i].x=rd(); e[i].y=rd();
        e[i].num=i; e[i].w1=rd(); e[i].w2=rd();
      }
      if(m){
        sort(e+1,e+1+m,cmp1);
        for(R int i=1;i<=m;++i)
          if(!ufs.judge(e[i].x,e[i].y)){
              ufs.merge(e[i].x,e[i].y);
              ans[++tot].p=e[i].num; ans[tot].x=1;
              res=max(res,e[i].w1); if((++cnt)==k) break;
          }
      }
      if(cnt<n-1){
        sort(e+1,e+1+m,cmp2);
        for(R int i=1;i<=m;++i)
          if(!ufs.judge(e[i].x,e[i].y)){
              ufs.merge(e[i].x,e[i].y);
              ans[++tot].p=e[i].num;
              if(e[i].w1<e[i].w2){ans[tot].x=1;res=max(res,e[i].w1);}
              else{ans[tot].x=2;res=max(res,e[i].w2);}
          }
      }
      printf("%d
    ",res);
      sort(ans+1,ans+1+tot,cmp3);
      for(R int i=1;i<=tot;++i) printf("%d %d
    ",ans[i].p,ans[i].x);
      return 0;
    }
    
  • 相关阅读:
    LeetCode#13罗马数字转整数
    LeetCode#7整数反转
    LeetCode#1两数之和
    LeetCode#26删除排序数组中的重复项
    LeecCode#1550存在连续三个奇数的数组
    LeetCode#228汇总区间
    LeetCode#1476子矩形查询
    LeetCode#1535找出数组游戏的赢家
    LeetCode#867转置矩阵
    Vue源码——摸着石头过河
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9672720.html
Copyright © 2011-2022 走看看