1. 程式人生 > >$[ HNOI 2006 ] $公路修建問題

$[ HNOI 2006 ] $公路修建問題

ans esp clas algorithm get std define res 還要


\(\\\)

\(Description\)


一個\(N\)個點\(M\)條邊的圖,每條邊可以選擇\(w_i,p_i\)兩個邊權之一,現求一個生成樹上的最大邊權最小值,要求這棵生成樹上至少有\(K\)條邊選擇的是\(w_i\)權值。\(Luogu\)上還要以"選了哪些編號的邊,每條邊選擇的是哪種權值"的形式求輸出方案。

  • \(N\in [1,10^4]\)\(M\in [0,2\times 10^4]\)\(K\in [0,N-1]\)\(w_i,p_i\in [1,3\times 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\n",res);
  sort(ans+1,ans+1+tot,cmp3);
  for(R int i=1;i<=tot;++i) printf("%d %d\n",ans[i].p,ans[i].x);
  return 0;
}

$[\ HNOI\ 2006\ ]\ $公路修建問題