P5198 [USACO19JAN]Icy Perimeter S (洛谷) (水搜索)

同样是因为洛谷作业不会写……

写(水)博客啦。

直接放题目吧,感觉放在代码框里好看点

Farmer John要开始他的冰激凌生意了!他制造了一台可以生产冰激凌球的机器,然而不幸的是形状不太规则,所以他现在希望优化一下这台机器,使其产出的冰激凌球的形状更加合理。 机器生产出的冰激凌的形状可以用一个N×N(1≤N≤1000)的矩形图案表示,例如:

##....
....#.
.#..#.
.#####
...###
....##
每个'.'字符表示空的区域,每个'#'字符表示一块1×1的正方形格子大小的冰激凌。

不幸的是,机器当前工作得并不是很正常,可能会生产出多个互不相连的冰激凌球(上图中有两个)。一个冰激凌球是连通的,如果其中每个冰激凌的正方形格子都可以从这个冰激凌球中其他所有的冰激凌格子出发重复地前往东、南、西、北四个方向上相邻的冰激凌格子所到达。

Farmer John想要求出他的面积最大的冰激凌球的面积和周长。冰激凌球的面积就是这个冰激凌球中'#'的数量。如果有多个冰激凌球并列面积最大,他想要知道其中周长最小的冰激凌球的周长。在上图中,小的冰激凌球的面积为2,周长为6,大的冰激凌球的面积为13,周长为22。

注意一个冰激凌球可能在中间有“洞”(由冰激凌包围着的空的区域)。如果这样,洞的边界同样计入冰激凌球的周长。冰激凌球也可能出现在被其他冰激凌球包围的区域内,在这种情况下它们计为不同的冰激凌球。例如,以下这种情况包括一个面积为1的冰激凌球,被包围在一个面积为16的冰激凌球内:

#####
#...#
#.#.#
#...#
#####
同时求得冰激凌球的面积和周长十分重要,因为Farmer John最终想要最小化周长与面积的比值,他称这是他的冰激凌的“冰周率”。当这个比率较小的时候,冰激凌化得比较慢,因为此时冰激凌单位质量的表面积较小。

输入格式
输入的第一行包含N,以下N行描述了机器的生产结果。其中至少出现一个'#'字符。

输出格式
输出一行,包含两个空格分隔的整数,第一个数为最大的冰激凌球的面积,第二个数为它的周长。如果多个冰激凌球并列面积最大,输出其中周长最小的那一个的信息。

这个……,搜索不香吗?遍历2遍(可能我写复杂了),效率是O(2n^2)(应该)。

感觉这个没什么可讲的,最重要的一点就是,面积一样大的冰激凌球,输出周长最小的一个。我因为这里WA了3次QWQ

我把要说的东西写在了注释上,看看就会明白的:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long a[1005][1005];
char c[1005][1005];
long long fx[5]={0,0,-1,1};//移动数组 
long long fy[5]={1,-1,0,0};
long long sz[1000005];
long long h[1000005];
long long n,bj,shu=1,cd,zshu=-1,shu2,zd=999999999;
void dfs(long long x,long long y)
{
	if(a[x][y]!=0||c[x][y]=='.')//不能走的格子,返回 
	{
		return;
	}
	a[x][y]=shu;//标记好连通块的编号 
	shu2++;//体积 
	bj=1; 
	for(int i=0;i<4;i++)
	{
		int zx=x+fx[i];//zx和zy是移动后的数。 
		int zy=y+fy[i];
		if(zx>=1&&zx<=n&&zy>=1&&zy<=n&&c[zx][zy]=='#')//可以走的格子,正常搜索 
		{
			dfs(zx,zy);//继续搜索 
		}
	}
}
void zc(long long x,long long y)//计算周长的函数 
{
	if(c[x][y]=='.')//这玩意不是#,退出 
	{
		return;
	}
	for(int i=0;i<4;i++)
	{
		if(c[x+fx[i]][y+fy[i]]!='#')//一个#的周长,就是看他旁边有多少个不是#的格子。 
		{
			h[a[x][y]]++; 
		}
	}
}
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>c[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			shu2=0;
			bj=0;
			dfs(i,j);
			if(bj!=0)//遇到了一个新的连通块 
			{
				if(zshu==shu2)//面积一样,处理。 
				{
					cd++;
					sz[cd]=shu;
				}
				if(zshu<shu2)//面积大,重置数组。 
				{
					cd=0;
					sz[cd]=shu;
					zshu=shu2; 
				}
				shu++;
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)//处理一下 
		{
			zc(i,j);
		}
	}
	for(int i=0;i<=cd;i++)//(感觉不打点什么有点空)输出 
	{
		zd=min(h[sz[i]],zd);
	}
	cout<<zshu<<" "<<zd<<endl;
	return 0;
}

(真水)

原文地址:https://www.cnblogs.com/lichangjian/p/13038135.html