【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel

给你一个网格(n<=2000,m<=2000),有一些炸弹,你可以选择一个空的位置,再放一个炸弹并将其引爆,一个炸弹爆炸后,其所在行和列的所有炸弹都会爆炸,连锁反应。

问你所能引爆的最多炸弹数。

转化成:

将行列当成点,炸弹当成边,然后你可以给这个二分图加1条边,问你最大的连通块的边的数量。

可以通过枚举所有可以建的边,通过并查集来尝试更新答案。由于一条边必然会让总度数+2,所以一个连通块的边数是所有点的度数之和/2。

并查集不必要动态维护集合的大小,一开始就建好并查集,提前统计好即可。

最后枚举的时候不会再在并查集之间再连边了,只会直接去更新答案。

队友的代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int Ans,num[6000],a[2003][2003],fa[6000],ans[6000],n,m,ansx,ansy;
char ch;
int get(int x) {
	return fa[x]==x?x:fa[x]=get(fa[x]);
}
void un(int x,int y)
{
	int X=get(x),Y=get(y);
	if(X!=Y) fa[X]=Y;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
			while(ch=getchar(),ch!='+'&&ch!='.');
			a[i][j]=ch;
			if(ch=='+')
			{
				num[i]++;
				num[j+n]++;
			}
		}
	}
	Ans=0;
	for(int i=1;i<=n+m;++i)
	{
		fa[i]=i;
	}
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	{
		if(a[i][j]=='+')
		{
			un(i,j+n);
		}
	}
	for(int i=1;i<=n+m;++i)
	{
		ans[get(i)]+=num[i];
	}
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	{
		if(a[i][j]=='.')
		{
			int nowans=ans[get(i)];
			if(get(i)!=get(j+n))
			{
				nowans+=ans[get(j+n)];
			}
			if(nowans/2>Ans)
			{
				Ans=nowans/2;
				ansx=i;
				ansy=j;
			}
		}
	}
	printf("%d\n",Ans);
	if(Ans)
	{
		printf("%d %d\n",ansx,ansy);
	}
	return 0;
}
posted @ 2017-08-04 21:16  AutSky_JadeK  阅读(456)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト