P4961 小埋与扫雷
题目背景
小埋总是在家中打游戏,一天,她突然想玩Windows自带的扫雷,在一旁的哥哥看见了,想起了自己小时候信息课在机房玩扫雷的日子,便兴致勃勃地开始教小埋扫雷。然而,小埋还是不明白 3bv(Bechtel’s Board Benchmark Value,每局将所有非雷的方块点开所需最少左键点击数,参见扫雷网的教程 )怎么算,于是她找到了你。
题目描述
小埋会告诉你一盘扫雷,用一个 n×m 的矩阵表示,1 是雷 ,0 不是雷,请你告诉她这盘扫雷的 3bv 。
周围八格没有“雷”且自身不是“雷”的方格称为“空格”,周围八格有“雷”且自身不是“雷”的方格称为“数字”,由“空格”组成的八连通块称为一个“空”。3bv= 周围八格没有“空格”的“数字”个数++“空"的个数。
如果看不懂上面的计算方式,可以看题目背景中给出的教程,或者看下面的样例解释。
注:八连通
输入格式
第一行有两个整数 n 和 m,代表这盘扫雷是一个n×m 的矩阵。
后面的 n 行每行有 m 个整数,表示这个矩阵,每个数字为 0 或 1,1 代表是雷,0 代表不是雷。
输出格式
一个整数,代表这盘扫雷的 3bv 。
输入输出样例
输入
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
输出
13
思路
1.输入
2.标记“数字”和“空格”
3.记录“空”的个数
4.计数:周围八格没有“空格”的“数字”个数
5.输出
#include<bits/stdc++.h>
using namespace std;
int n,m;
int pos[1005][1005];//1:雷,2:空格,3:数字
bool vis[1005][1005];
int ans;
int dx[8]={1,1,1,0,0,-1,-1,-1},dy[8]={1,0,-1,1,-1,1,0,-1};
void find(int x,int y){//判断它是数字还是空格
bool lei=false;
//先判断周围是否有雷:如果有雷,那就不必再继续下去了
for(int i=0;i<8&&!lei;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx>0&&tx<=n&&ty>0&&ty<=m){
if(pos[tx][ty]==1)
lei=true;
}
}
if(!lei){//无雷为空格:2
pos[x][y]=2;
} else{
pos[x][y]=3;
}
return ;
}
//判断八连通块
void dfs(int x,int y){
vis[x][y]=true;
for(int i=0;i<8;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx>0&&tx<=n&&ty>0&&ty<=m){
if(pos[tx][ty]==2&&!vis[tx][ty])
dfs(tx,ty);
}
}
return;
}
bool check(int x,int y){
bool st=true;
//如果已经出现了 空格:2,那就没有必要再继续搜下去了
for(int i=0;i<8&&st==true;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx>0&&tx<=n&&ty>0&&ty<=m){
if(pos[tx][ty]==2)
st=false;
}
}
return st;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>pos[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!pos[i][j])//只有自身不是雷,才能判断是数字还是空格
find(i,j);
}
}
//由“空格”组成的八连通块称为一个“空”,这里找到连通块的个数
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(pos[i][j]==2&&!vis[i][j]){
dfs(i,j);
ans++;
}
}
}
//周围八格没有“空格”的“数字”个数
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
if(pos[i][j]==3){//先判断它是不是数字:3
if(check(i,j))//判断它周围是否有空格:2
ans++;
}
}
cout<<ans;
return 0;
}