首先我屡教不改的在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;
}