二分(分块)枚举 边权上限。用kruscal判可行性。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int u[20001],v[20001],w1[20001],w2[20001],n,m,K,Limit; int fa[10001],rank[10002]; void init() { for(int i=1;i<=n;i++) fa[i]=i; memset(rank,0,(n+1)*sizeof(int)); } int findroot(int x) { if(x==fa[x]) return x; int rt=findroot(fa[x]); fa[x]=rt; return rt; } void Union(const int &U,const int &V) { if(rank[U]<rank[V]) fa[U]=V; else { fa[V]=U; if(rank[U]==rank[V]) ++rank[U]; } } bool Kruscal(int x)//仅仅需要接通即可。 { init(); int cnt=0; for(int i=1;i<=m;++i) if(w1[i]<=x) { int f1=findroot(u[i]),f2=findroot(v[i]); if(f1!=f2) { Union(f1,f2); ++cnt; if(cnt==n-1) return 1; } } if(cnt<K) return 0; for(int i=1;i<=m;++i) if(w2[i]<=x) { int f1=findroot(u[i]),f2=findroot(v[i]); if(f1!=f2) { Union(f1,f2); ++cnt; if(cnt==n-1) return 1; } } return cnt==n-1?1:0; } int main() { scanf("%d%d%d",&n,&K,&m); for(int i=1;i<=m;++i) { scanf("%d%d%d%d",&u[i],&v[i],&w1[i],&w2[i]); Limit=max(Limit,w1[i]); } int sz=sqrt(Limit),last=0; for(int i=1;last<=Limit;i+=sz) { if(Kruscal(i)) for(int j=last+1;j<=i;++j) if(Kruscal(j)) { printf("%d\n",j); return 0; } last=i; } }
时间: 2024-10-28 16:19:40