#kruskal,並查集#jzoj 1255 洛谷 2323 公路修建問題
阿新 • • 發佈:2018-12-16
題目
求一個無向圖的最小生成樹,且最小生成樹上的邊至少有k條是1級公路(保證單條公路費用一級 二級)
分析
kruskal先按一級最小後二級最大排序,求出前 條1級公路,再按二級最小排序求出 條公路
程式碼
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <climits>
#define rr register
#define min(a,b) ((a)<(b))?(a):(b)
#define max(a,b) ((a)>(b))?(a):(b)
using namespace std;
struct node{int x,y,w1,w2,rk;}e[20001];
int f[10001],n,k,m,t[10001],ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+ (ans<<1)+c-48,c=getchar();
return ans;
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed cmp1(node a,node b){return (a.w1!=b.w1)?(a.w1<b.w1):(a.w2>b.w2);}
signed cmp2(node a,node b){return a.w2<b.w2;}
signed cmp3(node a,node b){return a.rk<b.rk;}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
signed main(){
n=iut(),k=iut(),m=iut(); rr int tt=k;
for (rr int i=1;i<m;++i) e[i]=(node){iut(),iut(),iut(),iut(),i};
sort(e+1,e+m,cmp1);
for (rr int i=1;i<=n;++i) f[i]=i;
for (rr int i=1;i<m;++i){
rr int fa=getf(e[i].x),fb=getf(e[i].y);
if (fa==fb) continue;//kruskal思想
f[min(fa,fb)]=max(fa,fb);
e[i].w2=INT_MAX;
ans=max(ans,e[i].w1);
t[k--]=e[i].rk; if (!k) break;
}
sort(e+1,e+m,cmp2);
for (rr int i=1;i<m;++i)
if (e[i].w2!=INT_MAX){
rr int fa=getf(e[i].x),fb=getf(e[i].y);
if (fa==fb) continue;
f[min(fa,fb)]=max(fa,fb);
ans=max(ans,e[i].w2);
t[++tt]=e[i].rk; if (tt==n-1) break; //選完n-1條邊
}
sort(t+1,t+n); sort(e+1,e+m,cmp3); print(ans);
for (rr int i=1;i<n;++i){
putchar(10); print(t[i]);
putchar(32); putchar(50-(e[t[i]].w2==INT_MAX));//睿智輸出
}
return 0;
}