概括一下 就是最小生成树问题对于连接两个点的一条边都可以选择两个权值(一级 二级),一级权值>=二级,要求必须选至少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;
}