题目背景
小埋总是在家中打游戏,一天,她突然想玩Windows自带的扫雷,在一旁的哥哥看见了,想起了自己小时候信息课在机房玩扫雷的日子,便兴致勃勃地开始教小埋扫雷。然而,小埋还是不明白 3bv(Bechtel's Board Benchmark Value,每局将所有非雷的方块点开所需最少左键点击数,参见扫雷网的教程 )怎么算,于是她找到了你。
题目描述
小埋会告诉你一盘扫雷,用一个 n×m 的矩阵表示,1 是雷 ,0 不是雷,请你告诉她这盘扫雷的 3bv 。
周围八格没有“雷”且自身不是“雷”的方格称为“空格”,周围八格有“雷”且自身不是“雷”的方格称为“数字”,由“空格”组成的八连通块称为一个“空”。3bv= 周围八格没有“空格”的“数字”个数++“空"的个数。
如果看不懂上面的计算方式,可以看题目背景中给出的教程,或者看下面的样例解释。
注:八连通
输入格式
第一行有两个整数 n 和 m,代表这盘扫雷是一个 n×m 的矩阵。
后面的 n 行每行有 m 个整数,表示这个矩阵,每个数字为 0 或 1,1 代表是雷,0 代表不是雷。
输出格式
一个整数,代表这盘扫雷的 3bv 。
输入输出样例
输入 #1复制
8 8 0 0 0 1 1 0 0 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
输出 #1复制
13
说明/提示
1≤n, m≤1000
样例解释
#include<bits/stdc++.h>
using namespace std;
const int r[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}}; //用数组记录8个方向便于枚举
void dfs(int x,int y);
int n,m,mp[1010][1010],ans;
bool vis[1010][1010];
int main()
{
memset(mp,-1,sizeof(mp));
cin>>n>>m;
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
cin>>mp[i][j];
}
}
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
if (mp[i][j]==1)
{
for (int k=0;k<8;++k)
{
if (mp[i+r[k][0]][j+r[k][1]]==0)
{
mp[i+r[k][0]][j+r[k][1]]=2;
ans++;
}
}
}
}
}
for (int i=1;i<=n;++i)
{
for (int j=1;j<=m;++j)
{
if (mp[i][j]==0&&!vis[i][j])
{
dfs(i,j);
ans++;
}
}
}
cout<<ans;
return 0;
}
void dfs(int x,int y)
{
if (vis[x][y]||mp[x][y]==-1)
{
return;
}
vis[x][y]=true;
if (mp[x][y]==0)
{
for (int i=0;i<8;++i)
{
dfs(x+r[i][0],y+r[i][1]);
}
}
else
{
ans--;
}
}
思路: 广度优先搜索,求出所有的数字和空格,对每个空格dfs求空的个数,最后对每个数字判断周围是否有空格。