概括一下 就是最小生成樹問題對於連接兩個點的一條邊都可以選擇兩個權值(一級 二級),一級權值>=二級,要求必須選至少k條一級公路(因爲一級權值始終比二級全職大,所以我們就選k條一級公路),求這樣構建出來的最小生成樹最長的一條大小與選擇第幾條公路和級別。
這裏我們需要寫三個排序函數,第一個按照一級公路權值由小到大排序,選出k條公路。第二個按照二級公路權值由小到大排序,選出n-1-k條公路,記錄下來答案需要的值後最後進行第三次排序,按照公路序號由小到大排,輸出結果。注意這裏枚舉的是每一條邊後在判斷各種條件....之前瘋狂WA,還要注意題目給的是m-1條公路,以及調用快排函數時的各種範圍(.....)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=10010;
const int maxm=50010;
int n,m,k;
int ans=-100;
int fa[maxn];
struct edge{
int u,v,w1,w2;
int t;
}e[maxm*2];
struct print{
int first;
int second;
}qwq[maxm*2];
int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
bool cmp1(const edge &a,const edge &b)
{
if(a.w1==b.w1) return a.w2>b.w2;
return a.w1<b.w1;
}
bool cmp2(const edge &a,const edge &b)
{
return a.w2<b.w2;
}
void kruskal()
{
int now=0;
for(int i=1;i<=m;i++)
{
int f1=find(e[i].u);
int f2=find(e[i].v);
if(f1!=f2)
{
fa[f1]=fa[f2];
ans=max(ans,e[i].w1);
qwq[now].first=e[i].t;
qwq[now].second=1;
now++;
if(now==k) break;
}
}
sort(e+1,e+m,cmp2);
for(int i=1;i<=m;i++)
{
int f1=find(e[i].u);
int f2=find(e[i].v);
if(f1!=f2)
{
fa[f1]=fa[f2];
ans=max(ans,e[i].w2);
qwq[now].first=e[i].t;
qwq[now].second=2;
now++;
if(now==n-1) break;
}
}
}
bool cmp3(const print &a,const print &b)
{
return a.first<b.first;
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<=m-1;i++)
{
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w1,&e[i].w2);
e[i].t=i;
}
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
sort(e+1,e+m,cmp1);
kruskal();
sort(qwq,qwq+n-1,cmp3);
printf("%d\n",ans);
for(int i=0;i<=n-2;i++)
{
printf("%d %d\n",qwq[i].first,qwq[i].second);
}
return 0;
}