题目背景
小埋总是在家中打游戏,一天,她突然想玩Windows自带的扫雷,在一旁的哥哥看见了,想起了自己小时候信息课在机房玩扫雷的日子,便兴致勃勃地开始教小埋扫雷。然而,小埋还是不明白 每局将所有非雷的方块点开所需最少左键点击数,参见扫雷网的教程 )怎么算,于是她找到了你。
题目描述
小埋会告诉你一盘扫雷,用一个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
首先解释一下3bv,一个点会显示出四周8个点中有几个雷,对于一个3bv即为值为0的点联通块(同时联通块周围的所有点也视为在这个3bv内)或一个不属于任一联通块的一个四周有雷的点,(1,1)(1,2)(1,3)(2,2)(2,3)........这些都是
这样其是很容易就可以联想到一个很经典的问题填充颜色, 对于零的联通块进行dfs填充颜色,在填充的时候可以可以记录块的个数,最后剩下的块就是雷与距离3bv所差的块数,所以可以减去3bv = 0的联通块数 + n*m - 联通块一共所占的块数(包括0的联通块周围的那些块) - 雷的数目;这个问题就这样解决了。
贴代码:
#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){
int x = 0;int f = 1;char c = getchar();
while(c<'0'||c>'9'){
if(c == '-')f = -f;
c = getchar();
}
while(c<='9' && c>='0'){
x = x*10 + c - '0';
c = getchar();
}
return x*f;
}
int n,m,ans,tot,cnt;
int pic[2000][2000];
void dfs(int x,int y){
if(x <= n&&x >= 1 && y <= m&& y >= 1&&pic[x][y] == 0){
pic[x][y] = -1;
cnt++;
dfs(x+1,y);
dfs(x,y+1);
dfs(x,y-1);
dfs(x-1,y);
dfs(x + 1,y+1);
dfs(x + 1,y-1);
dfs(x-1,y-1);
dfs(x-1,y+1);
}
else if(x <= n&&x >= 1 && y <= m&& y >= 1&&pic[x][y]==9&&(pic[x-1][y]==-1||pic[x+1][y]==-1||pic[x][y+1]==-1||pic[x][y-1]==-1)){
pic[x][y] = -1;
cnt++;
}
}
int main(){
n = read(); m = read();
for(int i = 1; i<= n;i++) {
for(int j = 1; j<=m; j++){
pic[i][j] = read();
if(pic[i][j] == 1)tot++;
}
}
for(int i = 1; i<=n; i++){
for(int j = 1; j<=m; j++){
if(pic[i][j] == 1){
if(pic[i+1][j] != 1)pic[i+1][j] = 9;
if(pic[i][j+1] != 1)pic[i][j+1] = 9;
if(pic[i][j-1] != 1)pic[i][j-1] = 9;
if(pic[i-1][j] != 1)pic[i-1][j] = 9;
if(pic[i+1][j+1] != 1)pic[i+1][j+1] = 9;
if(pic[i+1][j-1] != 1)pic[i+1][j-1] = 9;
if(pic[i-1][j+1] != 1)pic[i-1][j+1] = 9;
if(pic[i-1][j-1] != 1)pic[i-1][j-1] = 9;
}
}
}
for(int i = 1; i<=n;i ++){
for(int j = 1; j<=m; j++){
if(pic[i][j] == 0){
dfs(i,j);/*
for(int k = 1; k<=n; k++){
for(int p = 1; p<=m ;p++){
cout<<pic[k][p]<<' ';
}
cout<<'\n';
}
cout<<cnt<<'\n';*/
ans++;
}
}
}
printf("%d ",ans+n*m-cnt-tot);
return 0;
}