2420. Icy Perimeter
(File IO): input:perimeter.in output:perimeter.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制
Goto ProblemSet
题目描述
Farmer John要开始他的冰激凌生意了!他制造了一台可以生产冰激凌球的机器,然而不幸的是形状不太规则,所以他现在希望优化一下这台机器,使其产出的冰激凌球的形状更加合理。
机器生产出的冰激凌的形状可以用一个N×N(1≤N≤1000)的矩形图案表示,例如:
每个’.‘字符表示空的区域,每个’#‘字符表示一块1×1的正方形格子大小的冰激凌。
不幸的是,机器当前工作得并不是很正常,可能会生产出多个互不相连的冰激凌球(上图中有两个)。一个冰激凌球是连通的,如果其中每个冰激凌的正方形格子都可以从这个冰激凌球中其他所有的冰激凌格子出发重复地前往东、南、西、北四个方向上相邻的冰激凌格子所到达。
Farmer John想要求出他的面积最大的冰激凌球的面积和周长。冰激凌球的面积就是这个冰激凌球中’#'的数量。如果有多个冰激凌球并列面积最大,他想要知道其中周长最小的冰激凌球的周长。在上图中,小的冰激凌球的面积为2,周长为6,大的冰激凌球的面积为13,周长为22。
注意一个冰激凌球可能在中间有“洞”(由冰激凌包围着的空的区域)。如果这样,洞的边界同样计入冰激凌球的周长。冰激凌球也可能出现在被其他冰激凌球包围的区域内,在这种情况下它们计为不同的冰激凌球。例如,以下这种情况包括一个面积为1的冰激凌球,被包围在一个面积为16的冰激凌球内:
同时求得冰激凌球的面积和周长十分重要,因为Farmer John最终想要最小化周长与面积的比值,他称这是他的冰激凌的“冰周率”。当这个比率较小的时候,冰激凌化得比较慢,因为此时冰激凌单位质量的表面积较小。
输入
输入的第一行包含N,以下N行描述了机器的生产结果。其中至少出现一个’#'字符。
输出
输出一行,包含两个空格分隔的整数,第一个数为最大的冰激凌球的面积,第二个数为它的周长。如果多个冰激凌球并列面积最大,输出其中周长最小的那一个的信息。
样例输入
6
##....
....#.
.#..#.
.#####
...###
....##
样例输出
13 22
题目没什么好讲的,就是一道搜索模板题。
我考试时用了dfs,但是有一个点没过,听网上大佬们说,是爆栈了。只怨我才疏学浅,还是不懂
最后通过特判,才将dfs改对。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int dx[8]={-1,1,0,0};
const int dy[8]={0,0,-1,1};
int n,ans,ans1,maxn,sum,maxc,c[1010][1010];
char a[1010][1010];
bool f[1010][1010];
void input()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
char s;
cin>>s;
if(s=='#') sum++; //特判全是‘#’
a[i][j]=(s=='.')?0:1;
}
}
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&!f[nx][ny]&&a[nx][ny])
{
f[nx][ny]=1;
ans++;
ans1+=c[nx][ny];
dfs(nx,ny);
}
}
}
void zc()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j])
{
if(!a[i-1][j]) c[i][j]++;
if(!a[i+1][j]) c[i][j]++;
if(!a[i][j-1]) c[i][j]++;
if(!a[i][j+1]) c[i][j]++;
}
}
int main()
{
fre(perimeter);
input();
if(sum==n*n)
{
printf("%d %d\n",sum,4*n);
return 0;
}
zc();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]&&!f[i][j])
{
ans=1,ans1=c[i][j];
f[i][j]=1;
dfs(i,j);
if(maxn<ans) maxn=ans,maxc=ans1;
if(maxn==ans) maxc=min(maxc,ans1);
}
printf("%d %d\n",maxn,maxc);
return 0;
}
bfs就没问题,也是个模板。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
struct node {int x,y;}q[1000010];
const int dx[8]={-1,1,0,0};
const int dy[8]={0,0,-1,1};
int n,ans,ans1,maxn,sum,maxc,c[1010][1010];
char a[1010][1010];
bool f[1010][1010];
void input()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
char s;
cin>>s;
a[i][j]=(s=='.')?0:1;
}
}
void bfs(int sx,int sy)
{
int head=0,tail=1;
q[1].x=sx,q[1].y=sy;
while(head<=tail)
{
head++;
int tx=q[head].x,ty=q[head].y;
for(int i=0;i<4;i++)
{
int nx=tx+dx[i],ny=ty+dy[i];
if(a[nx][ny]&&!f[nx][ny]&&nx>=1&&nx<=n&&ny>=1&&ny<=n)
{
tail++;
q[tail].x=nx,q[tail].y=ny;
f[nx][ny]=1;
ans++;
ans1+=c[nx][ny];
}
}
}
}
void zc()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j])
{
if(!a[i-1][j]) c[i][j]++;
if(!a[i+1][j]) c[i][j]++;
if(!a[i][j-1]) c[i][j]++;
if(!a[i][j+1]) c[i][j]++;
}
}
int main()
{
fre(perimeter);
input();
zc();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]&&!f[i][j])
{
ans=1,ans1=c[i][j];
f[i][j]=1;
bfs(i,j);
if(maxn<ans) maxn=ans,maxc=ans1;
if(maxn==ans) maxc=min(maxc,ans1);
}
printf("%d %d\n",maxn,maxc);
return 0;
}
经验教训:对于极值能用特判就特判,毕竟搜索慢;当然能用bfs就别用dfs(递归太深,会爆栈)。