题目描述:
点击进入题目
Jimmy 和 Symbol 约好一起看星星,浩瀚的星空可视为一个长为 N、宽为 M的矩阵,矩阵中共有
N
×
M
N \times M
N×M个位置,一个位置可以用坐标
(
i
,
j
)
(
1
≤
i
≤
N
,
1
≤
j
≤
M
)
(i,j)(1 ≤i≤N,1\le j≤M)
(i,j)(1≤i≤N,1≤j≤M)来表示。每个位置上可能是空的,也可能有一个星星。
对于一个位置 ( i , j ) (i,j) (i,j),与其相邻的位置有左边、左上、上面、右上、右边、右下、下面、左下 8 个位置。相邻位置上的星星被视为同一个星座,这种关系有传递性,例如若 ( 1 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) ( 1 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) (1,1),(1,2),(1,3)(1,1),(1,2),(1,3) (1,1),(1,2),(1,3)(1,1),(1,2),(1,3)三个 位置上都有星星,那么这三个星星视为同一个星座。包含的星星数量相同的星座被视为一个星系(一个星系中的星座不一定相邻),星系的大小为星系中包含的所有星星数量。
由于 Symbol 太喜欢星系了,他就想考一考 Jimmy,让 Jimmy 求出星空中有多少个星系,他还想知道,最大的星系有多大。
题意理解:
这是一道flood fill模型的题,和NOI池塘计数很相近的题目,因为要返回星座中星星的数量,所以我们可以把BFS的返回值改成星星数量。
由题目得出星星数量相同的是一个星系,那么直接用星星数量作为下标(b[N]),并统计次数,二者相乘就是星系中星星的数量,那么不断取最大值即可。
思路分解:
-
BFS的Flood Fill洪水灌溉模型先麻溜地打起来
-
每次通过新的星星“种子”去BFS时要把这次发现的星星数量计数并返回
-
针对返回的星星数量,统计出现次数,如果未曾出现过这个数量就星系个数加1
-
星星数量和出现次数相乘后为当前星系的星星总数,不断取max获得最终的最大星系星星总数(稍微有点绕),小心理解一下。
代码:
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N=1505,M=100005;
int n,m;
char g[N][N];
PII q[N*N];//手写队列
int b[M];
int ans,res;
int bfs(int sx,int sy)
{
int cnt=1,hh=0,tt=0;
q[0]={sx,sy};
g[sx][sy]='.';
while(hh<=tt)
{
PII t=q[hh++];
for(int i=t.x-1; i<=t.x+1; i++)
{
for(int j=t.y-1; j<=t.y+1; j++)
{
if(i==t.x && j==t.y) continue;
if(i<0 || i>=n || j<0 || j>=m) continue;
if(g[i][j]=='.') continue;
q[++tt]={i,j};
g[i][j]='.';
cnt++;
}
}
}
return cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
scanf("%s",&g[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(g[i][j]=='*')
{
int k=bfs(i,j);
if(!b[k])
res++;
b[k]++;
ans=max(ans,b[k]*k);
}
}
}
printf("%d %d\n",res,ans);
return 0;
}
注意事项
- 用数组模拟队列时,最差情况下要把所有的星星都探测一遍,所以规模是N*N