题目
求一个无向图的最小生成树,且最小生成树上的边至少有k条是1级公路(保证单条公路费用一级 ≥ \geq ≥二级)
分析
kruskal先按一级最小后二级最大排序,求出前 k k k条1级公路,再按二级最小排序求出 n − 1 − k 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;
}