公路修建问题题解
公路修建问题题解
一看到题目中“花费最大的公路最小”,
我们就想到了二分,
于是乎,我们就有了最大的边x,
还需要满足的条件是:
1.有k条花费小于x的一级公路,且这k条不构成环(因为是要树中有k条一级公路)
2.所有花费小于x的公路能构成一条最小生成树
用并查集维护连通,用Kruskal的思想能加就尽量加。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=20006;
int n,k,m,p,t,f[N];
struct xd{int x,y,c1,c2;}a[N];
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
bool merge(int u,int v){
u=getf(u),v=getf(v);
if(u==v) return 0;
f[u]=v; return 1;
}
bool check(int u){
p=0;
for(int i=1;i<=n;++i) f[i]=i;
for(int i=1;i<=m;++i) if(a[i].c1<=u) if(merge(a[i].x,a[i].y)) ++p;
if(p<k) return 0;
for(int i=1;i<=m;++i) if(a[i].c2<=u) if(merge(a[i].x,a[i].y)) ++p;
if(p<n-1) return 0;
return 1;
}
int ef(int l,int r){
int mid=(l+r>>1);
if(l==r) return l;
if(check(mid)) return ef(l,mid);
else return ef(mid+1,r);
}
int main(){
n=read(),k=read(),m=read()-1;
for(int i=1;i<=m;++i) a[i].x=read(),a[i].y=read(),a[i].c1=read(),a[i].c2=read();
t=ef(1,30000),printf("%d\n",t);
for(int i=1;i<=n;++i) f[i]=i;
for(int i=1;i<=m;++i) if(a[i].c1<=t) if(merge(a[i].x,a[i].y)) printf("%d %d\n",i,1);
for(int i=1;i<=m;++i) if(a[i].c2<=t) if(merge(a[i].x,a[i].y)) printf("%d %d\n",i,2);
return 0;
}