1. 程式人生 > >#kruskal,並查集#jzoj 1255 洛谷 2323 公路修建問題

#kruskal,並查集#jzoj 1255 洛谷 2323 公路修建問題

題目

求一個無向圖的最小生成樹,且最小生成樹上的邊至少有k條是1級公路(保證單條公路費用一級 \geq 二級)


分析

kruskal先按一級最小後二級最大排序,求出前 k k 條1級公路,再按二級最小排序求出 n

1 k n-1-k 條公路


程式碼

#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; }