题目背景
小埋总是在家中打游戏,一天,她突然想玩Windows自带的扫雷,在一旁的哥哥看见了,想起了自己小时候信息课在机房玩扫雷的日子,便兴致勃勃地开始教小埋扫雷。然而,小埋还是不明白 \mathrm{3bv}3bv(Bechtel's Board Benchmark Value,每局将所有非雷的方块点开所需最少左键点击数,参见扫雷网的教程 )怎么算,于是她找到了你。
题目描述
小埋会告诉你一盘扫雷,用一个 n\times mn×m 的矩阵表示,11 是雷 ,00 不是雷,请你告诉她这盘扫雷的 \mathrm{3bv}3bv 。
周围八格没有“雷”且自身不是“雷”的方格称为“空格”,周围八格有“雷”且自身不是“雷”的方格称为“数字”,由“空格”组成的八连通块称为一个“空”。\mathrm{3bv}=\3bv= 周围八格没有“空格”的“数字”个数++“空"的个数。
如果看不懂上面的计算方式,可以看题目背景中给出的教程,或者看下面的样例解释。
注:八连通
输入格式
第一行有两个整数 nn 和 mm,代表这盘扫雷是一个 n \times mn×m 的矩阵。
后面的 nn 行每行有 mm 个整数,表示这个矩阵,每个数字为 00 或 11,11 代表是雷,00 代表不是雷。
输出格式
一个整数,代表这盘扫雷的 \mathrm{3bv}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\le n,\ m\le 10001≤n, m≤1000
样例解释
上代码:
#include<bits/stdc++.h>//万能大法好
using namespace std;
int a[1000][1000],m,n;//a是雷图,mn是边界
bool booka[1000][1000];//联通快时判重
int xz[8]={-1,-1,-1,0,0,1,1,1},yz[8]={-1,0,1,-1,1,-1,0,1};//八联通!!!
int bv3,lt; //第一个3bv,lt是联通快的数量
void dfs(int x,int y)//联通快
{
for(int i=0;i<8;i++)
{
int xx=x+xz[i],yy=y+yz[i];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]==0&&!booka[xx][yy])//判断边界与重复
{
booka[xx][yy]=true;//打标记
dfs(xx,yy);
}
}
}
void b(int x,int y)//初始化雷图用的,把格子里填数字
{
for(int p=0;p<8;p++)
{
int i=x+xz[p],j=y+yz[p];
if(i>=0&&i<n&&j>=0&&j<m&&a[i][j]!=-1)
a[i][j]++;
}
}
int iff(int x,int y)//判断周围八格是否有空格
{
for(int i=0;i<8;i++)
{
int xx=x+xz[i];
int yy=y+yz[i];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]==0)//判空格
return 0;
}
return 1;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>a[i][j];
if(a[i][j]==1) a[i][j]=-1;//读入,把雷标记为-1,便于区分数字为 1的无雷格
}
}
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(a[i][j]==-1)
b(i,j);//把有雷格周围八格数字自增
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(a[i][j]!=0&&a[i][j]!=-1&&iff(i,j))
bv3++;//周围八格无雷的数字的数量
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(a[i][j]==0&&!booka[i][j])
{
lt++;//联通快数量
dfs(i,j);
}
}
}
bv3+=lt;
cout<<bv3;//输出答案
return 0;
}