题解【洛谷】P6566 NOI Online #3 入门组 观星

题目描述:

点击进入题目
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)1iN1jM来表示。每个位置上可能是空的,也可能有一个星星。

对于一个位置 ( 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]),并统计次数,二者相乘就是星系中星星的数量,那么不断取最大值即可。

思路分解:

  1. BFS的Flood Fill洪水灌溉模型先麻溜地打起来

  2. 每次通过新的星星“种子”去BFS时要把这次发现的星星数量计数并返回

  3. 针对返回的星星数量,统计出现次数,如果未曾出现过这个数量就星系个数加1

  4. 星星数量和出现次数相乘后为当前星系的星星总数,不断取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;
}

注意事项

  1. 用数组模拟队列时,最差情况下要把所有的星星都探测一遍,所以规模是N*N
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值