公路修建问题题解

本文探讨了在特定条件下寻找最大花费公路的最小值问题,采用二分查找结合Kruskal算法思想,确保生成的树中有k条一级公路且构成最小生成树。使用并查集维护连通性,通过代码实现了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

公路修建问题题解

一看到题目中“花费最大的公路最小”,

我们就想到了二分,

于是乎,我们就有了最大的边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;
} 

转载于:https://www.cnblogs.com/ljk123-de-bo-ke/p/11319028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值