原题链接:http://codeforces.com/contest/616/problem/C
说题之前先啰嗦几句:
说来从4月中旬到5月初一直在学java和前端,很长时间没有刷题了,感觉又落下了不少,学习新知识的过程中我看过很多有用的和没用的资料,最直观的感觉是,很多途径教你怎么速成一门手艺,但是却没有教你怎么深入进去,过程中我也认识了几个一起学习的小伙伴,觉得这些只注重速度的教学不是无中生有的,因为确实存在这麽一些人,他们恨不能用最短的时间吧所有都学完,甚至我有时也会不由自主的加快学习速度,从而使得我得到的新知识不能深入理解;
要说大学期间让我坚持这麽久还没有放弃的事情,应该就是刷题了,这周开始刷题,感觉脑细胞又重新运转起来了,走神的几率大大减少,不得不承认,算法的学习让我改变了大脑懒惰的坏习惯,想想总算有件事情能让我在大学期间学习的热情能有那么点儿提高了。。。
题解:
给你一个矩阵,有'*'和'.'两种字符,对于每一个字符'*',计算其上下左右四个方向所有相连的'.'的个数。
肯定不能直接对于每个'*'搜索,所以可以从'.'下手;于是我先dfs搜索记录每个'.'的联通块,并且要用一个数组记录连通块个数,这里标记时我们对于每个联通块用不同的数字标记,然后就可以对于每一个'*'上下左右搜索。这里要注意,搜索时,不同方向的'.'的个数可能是同一个联通块里面的,所以,要判重,一开始没有考虑到这点,就找了半小时错误。。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <map>
using namespace std;
int n, m;
char e[1005][1005];
int dir[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };
int vis[1005][1005];
int cnt, num;
set<int> s;
map<int, int> mp;
void dfs(int x, int y)
{
int i, j;
for (i = 0; i < 4; i++)
{
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if (tx <= 0 || tx > n || ty <= 0 || ty > m || vis[tx][ty] || e[tx][ty] == '*')
continue;
cnt++;
vis[tx][ty] = num;
dfs(tx, ty);
}
}
int main()
{
int i, j;
scanf("%d%d", &n, &m);
for (i = 1; i <= n; i++)
scanf("%s", e[i] + 1);
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
{
if (!vis[i][j] && e[i][j] == '.')
{
num++;
cnt = 1;
vis[i][j] = num;
dfs(i, j);
mp[num] = cnt;
}
}
for (i = 1; i <= n; i++){
for (j = 1; j <= m; j++)
{
if (e[i][j] == '*'){
int cc = 0;
s.clear();
for (int k = 0; k < 4; k++)
{
int tx = i + dir[k][0];
int ty = j + dir[k][1];
if (e[tx][ty] == '.'&&!s.count(vis[tx][ty]))
{
s.insert(vis[tx][ty]);
cc += mp[vis[tx][ty]];
}
}
printf("%d", (cc + 1) % 10);
}
else
printf("%c", e[i][j]);
}
printf("\n");
}
return 0;
}