码迷,mamicode.com
首页 > 其他好文 > 详细

【分块答案】【最小生成树】【kruscal】bzoj1196 [HNOI2006]公路修建问题

时间:2014-12-23 19:13:35      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:

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

【分块答案】【最小生成树】【kruscal】bzoj1196 [HNOI2006]公路修建问题

标签:

原文地址:http://www.cnblogs.com/autsky-jadek/p/4180555.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!