题目
这次的扫雷是二维的了。根据三种规则做一次判断,判断出一定是雷和一定不是雷的数量。
1.如果某一个被探明的格子里所标的数字为0,那么它相邻的8个格子里的未探明格子被认作是一定不是地雷的格子。
2.如果某一个被探明的格子里所标的数字为K,且它相邻的8个格子里正好有K个没有探明的格子的话,则这K个没有探明的格子被认作是一定是地雷的格子。
3.如果某两个探明了的格子A和B,他们中标明的数字分别为P_A和P_B,且他们周围8个格子中没有探明的格子组成的集合分别为S_A和S_B,如果S_A包含S_B,且|S_A|-|S_B|=P_A-P_B,那么S_A-S_B中的所有格子,被认作是一定是地雷的格子。
每次规则的推导应当视作独立的,即不基于任何其他推导出的结论进行。
第1行为2个整数N,M,表示迷宫的大小。
接下来的N行,每行M个整数,为一个矩阵A,用以描述整个迷宫,其中对于每一个格子A[i][j],若A[i][j]=-1,则表示该格子没有被探明,若0<=A[i][j]<=8,则表示该格子已经被探明了,且数值代表该格子附近8个格子中的地雷数。
对于100%的数据,满足:5<=N、M<=2*10^2, -1<=A[i][j]<=8。
思路
。。。。。
首先我规定:矩阵的行数从1开始,到N结束;列数从1开始,到M结束。-2为一定不是雷,-3是一定是雷。
就是根据三种规则写出不同的判断函数。
1.如果某一个被探明的格子里所标的数字为0,那么它相邻的8个格子里的未探明格子被认作是一定不是地雷的格子。
void run1(int x,int y)
{
for(int i=-1;i<=1;i++) if(x+i>=1 && x+i<=N)
for(int j=-1;j<=1;j++) if(y+j>=1 && y+j<=M && map[x+i][y+j]==-1)
map[x+i][y+j]=-2;
}
2.如果某一个被探明的格子里所标的数字为K,且它相邻的8个格子里正好有K个没有探明的格子的话,则这K个没有探明的格子被认作是一定是地雷的格子。
void run2(int x,int y)
{
if(caculateUnknow(x,y)==map[x][y])
{
for(int i=-1;i<=1;i++) if(x+i>=1 && x+i<=N)
for(int j=-1;j<=1;j++) if(y+j>=1 && y+j<=M && map[x+i][y+j]==-1)
map[x+i][y+j]=-3;
}
}
3.如果某两个探明了的格子A和B,他们中标明的数字分别为P_A和P_B,且他们周围8个格子中没有探明的格子组成的集合分别为S_A和S_B,如果S_A包含S_B,且|S_A|-|S_B|=P_A-P_B,那么S_A-S_B中的所有格子,被认作是一定是地雷的格子。
void run3(int x,int y)
{
for(int i=-2;i<=2;i++) if(x+i>=1 && x+i<=N)
for(int j=-2;j<=2;j++)
if(y+j>=1 && y+j<=M && (i || j) && map[x+i][y+j]>=0 && check(x+i,y+j,x,y))
{
if(map[x][y]-map[x+i][y+j]==caculateUnknow(x,y)-caculateUnknow(x+i,y+j))
{
for(int n=-1;n<=1;n++) if(x+n>=1 && x+n<=N)
for(int m=-1;m<=1;m++) if(y+m>=1 && y+m<=M && map[x+n][y+m]<0 && !isAdjacent(x+n,y+m,x+i,y+j))
map[x+n][y+m]=-3;
}
}
}
全代码
#include <cstdio>
#define SIZE 201
int N,M,map[SIZE][SIZE];
int count0,count1;
int isAdjacent(int i1, int j1, int i2, int j2)
{
if ((i1 - i2) > 1 || (i1 - i2)<-1 || (j1 - j2)>1 || (j1 - j2) < -1)
return 0;
else
return 1;
}
int caculateUnknow(int x, int y)
{
int i, j;
int count = 0;
for(int n=-1;n<=1;n++) if(x+n>=1 && x+n<=N)
for(int m=-1;m<=1;m++) if(y+m>=1 && y+m<=M && map[x+n][y+m]<0)
count++;
return count;
}
bool check(int x,int y,int a,int b)
{
for(int i=-1;i<=1;i++) if(x+i>=1 && x+i<=N)
for(int j=-1;j<=1;j++) if(y+j>=1 && y+j<=M && map[x+i][y+j]<0 && !isAdjacent(x+i,y+j,a,b))
return false;
return true;
}
void run1(int x,int y)
{
for(int i=-1;i<=1;i++) if(x+i>=1 && x+i<=N)
for(int j=-1;j<=1;j++) if(y+j>=1 && y+j<=M && map[x+i][y+j]==-1)
map[x+i][y+j]=-2;
}
void run2(int x,int y)
{
if(caculateUnknow(x,y)==map[x][y])
{
for(int i=-1;i<=1;i++) if(x+i>=1 && x+i<=N)
for(int j=-1;j<=1;j++) if(y+j>=1 && y+j<=M && map[x+i][y+j]==-1)
map[x+i][y+j]=-3;
}
}
void run3(int x,int y)
{
for(int i=-2;i<=2;i++) if(x+i>=1 && x+i<=N)
for(int j=-2;j<=2;j++)
if(y+j>=1 && y+j<=M && (i || j) && map[x+i][y+j]>=0 && check(x+i,y+j,x,y))
{
if(map[x][y]-map[x+i][y+j]==caculateUnknow(x,y)-caculateUnknow(x+i,y+j))
{
for(int n=-1;n<=1;n++) if(x+n>=1 && x+n<=N)
for(int m=-1;m<=1;m++) if(y+m>=1 && y+m<=M && map[x+n][y+m]<0 && !isAdjacent(x+n,y+m,x+i,y+j))
map[x+n][y+m]=-3;
}
}
}
int main()
{
int K;
scanf("%d",&K);
while(K--)
{
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
scanf("%d",&map[i][j]);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
{
if(!map[i][j])
{
run1(i,j);
}
if(map[i][j]>0)
{
run2(i,j);
run3(i,j);
}
}
count0=count1=0;
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
if(map[i][j]==-2) count0++;
if(map[i][j]==-3) count1++;
}
}
printf("%d %d\n",count1,count0);
}
return 0;
}