【BZOJ1821】【JSOI2010】Group 部落划分 Group (两个group什么意思

这篇博客探讨了BZOJ1821和JSOI2010中关于部落划分的问题,通过二分答案和贪心策略来解决。作者指出,随着部落数量减少,边的合并是单调的。解决方案涉及构建最小生成树,并在树中找到特定边作为答案。部落合并时,不仅考虑直接连接的边,还有可能影响其他边。最终,利用最小生成树的性质,可以快速确定第n-m+1条边为答案。
摘要由CSDN通过智能技术生成

首先我们可以考虑到二分答案+贪心。

每次check把一切边权小于mid的点对合并到一个并查集里面。

然后分析这个的正确性,发现每当mid变大,那么部落数就会减少,而且是单调的。


但是有了这个作为基础。

我们就可以延展到迭代的思想上,,然后……


然后考虑到如果各为部落,那么答案一定是所有的边中最小的边,

而此时我们如果要合并某些部落,就会导致一些边被删除

(注意:合并两个部落,那么被删除的边不一定只有这俩部落的连边,,这个太水了,不细说)


此时答案,又是所有边中最小的边。


那么显然——答案一定在最小生成树中。

这个自己脑补一下很快就出来了。


所以我们可以建立一颗最小生成树,然后记录树边,然后O(1)就可以出解了。

现在分析这个O(1)是怎么个O(1)!

有n个人,m个部落,那么原来的最小生成树n-1条边,新的最小生成树m-1条边,也就是删除了n-m条边

所以最小生成树的第n-m+1条边就是答案。


代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1050
#define inf 0x3f3f3f3f
using namespace std;
int n,m,x[N],y[N],cnt;
struct ROAD
{
	int u,v,len;
	bool operator < (const ROAD &a)const{return len<a.len;}
	ROAD(int _u,int _v,int _len):u(_u),v(_v),len(_len){}
	ROAD(){}
}road[N*N];
int f[N],id;
int find(int x)
{
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
int main()
{
//	freopen("test.in","r",stdin);
//	freopen("my.out","w",stdout);
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
	for(i=1;i<=n;i++)
	{
		f[i]=i;
		for(j=i+1;j<=n;j++)road[++id]=ROAD(i,j,(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
	}
	sort(road+1,road+id+1);
	m=n-m;
	for(i=1;i<=id;i++)
	{
		int fu=find(road[i].u),fv=find(road[i].v);
		if(fu==fv)continue;
		f[fv]=fu;
		if(++cnt>m)
		{
			printf("%.2lf\n",sqrt(road[i].len));
			return 0;
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值