二分(分块)枚举 边权上限。用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;
	  }
}

相关文章:

  • 2022-12-23
  • 2022-02-06
  • 2021-12-29
  • 2021-07-10
  • 2021-09-04
  • 2021-07-30
  • 2021-06-25
猜你喜欢
  • 2022-12-23
  • 2021-06-23
  • 2021-05-28
  • 2021-07-04
  • 2021-06-20
  • 2022-12-23
相关资源
相似解决方案