「做题笔记」P6566 [NOI Online #3 入门组]观星

首先我屡教不改的在NOIOL前懒得搞dfs。
嗯,100分香啊(


然后这个题目有点绕人,我们得搞清楚几个定义:

  • 星星:一个*视为一个星星
  • 星座:如果 (a_{i,j}) 是星星,那么如果与之相邻的八个方向的任意一个 (a_{i',j'}) 也是星星就构成了一个星座。需要注意星座有传递性,例如这是一个星座:**,但这也是一个星座:*****
  • 星系、星系大小:包含数量相同的星座视为一个星系,星系的大小是星系所包含的所有星座内含有的星星数量。

于是就可以有多少个星系我们就能求了。用viscnt[i]表示大小为 (i) 的星座是不是第一次出现。每次遇到一个*就dfs一次,如果dfs得到的大小此前已经有过,说明是同一个星系,不管就好;否则答案加一。

那么如何求出最大的星系大小呢?其实很简单,只需要做一些小小的改动:viscnt[i]不仅表示大小为 (i) 的星座是不是第一次出现,如果是出现的,还表示当前这个星系的大小。然后如果是同一个星系就要令viscnt[i]+=i,然后答案更新;否则令viscnt[i]=i,然后更新答案就好了。星系的数量照样求。

然后5min就干出了这题的代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define MAXN 2020

using namespace std;

int n , m , a[ MAXN ][ MAXN ];
char ch;
int cnt , viscnt[ 1000020 ] , maxcnt = -99999999;
int dx[10] = { 0 , 1 , -1 , 0 , 0 , -1  , 1 , -1 , 1 } , dy[10] = { 0 , 0 , 0 , 1 , -1 , 1 , -1 , -1 , 1 };

void dfs( int x , int y )
{
	if( !a[x][y] || x > n || y > m || x < 0 || y < 0 ) return ;
	a[x][y] = 0;
	cnt++;
	for( int i = 1 ; i <= 8 ; i++ )
		dfs( x + dx[i] , y + dy[i] );
} //这是一个正常的dfs求连通块的写法。

int main()
{
	cin >> n >> m;
	for( int i = 1 ; i <= n ; i++ )
		for( int j = 1 ; j <= m ; j++ )
		{
			cin >> ch;
			if( ch == '*' ) a[i][j] = 1; 
			else a[i][j] = 0;
                        //实现字符->数字的映射。
		}
	int ans = 0;
	for( int i = 1 ; i <= n ; i++ )
		for( int j = 1 ; j <= m ; j++ )
		{
			if( a[i][j] )
			{
				cnt = 0; //把上一次的结果清灵。
				dfs( i , j );
				if( !viscnt[ cnt ] )
				{
					ans++;
					viscnt[ cnt ] += cnt;
					maxcnt = max( cnt , maxcnt );
				}
				else
				{
					viscnt[ cnt ] += cnt;
					maxcnt = max( viscnt[ cnt ] , maxcnt );
				}
			} 
		}
	cout << ans << " " << maxcnt << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/BlueInRed/p/13046940.html