【蓝桥杯每日一题】4.4 扫雷

题目来源:

687. 扫雷 - AcWing题库

参考:y总视频讲解

问题描述:

  • 找到解决扫雷游戏中的最小点击次数

思考:

为了保证胜利且每个格子只能走一次,所以当遇到地雷或检测到该格子周围存在地雷的时候就需要停止搜索,那么如何知道当前的格子的周围是否存在地雷呢?

可以用一个二维数组 n u m num num来统计每个位置周围的地雷数量,例如,当前位置为 ( 2 , 2 ) (2,2) (2,2)则就需要查看 ( 1 , 1 ) (1,1) (1,1) ( 1 , 2 ) (1,2) (1,2) ( 1 , 3 ) (1,3) (1,3) ( 2 , 1 ) (2,1) (2,1) ( 2 , 3 ) (2,3) (2,3) ( 3 , 1 ) (3,1) (3,1) ( 3 , 2 ) (3,2) (3,2) ( 3 , 3 ) (3,3) (3,3)的位置是否存在地雷,如果存在就把 ( 2 , 2 ) (2,2) (2,2)位置的地雷数量 + 1 +1 +1。由于题目中求最小点击次数,在我们每次点击 0 0 0位置时,其周围的所有 0 0 0都会被点亮,所以我们可以把每个为 0 0 0的位置进行搜索并进行标记 表示已经扫描过了一次,并且将点击次数 + 1 +1 +1。最后再进行一次遍历,将所有状态不为 0 0 0的格子进行点击即可求出最小点击次数。

步骤:

  • 使用num数组来表示当前位置周围的地雷数量,如果当前位置就是地雷,那么设置为-1。
  • 遍历num数组,如果当前位置为0,即周围没有地雷,则进行搜索,将其周围所有为0的点进行标记,直到num不为0时停止。
    最后统计没有被标记为-1的结点数量,累加,即为最后结果

AC Code:

c++ 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N=310;
int dx[8]={1,1,1,0,0,-1,-1,-1};
int dy[8]={1,0,-1,1,-1,1,0,-1};
char m[N][N];  //整个的地图
int num[N][N];  //显示的数字
bool vis[N][N]; //遍历的记录

int t,n;
int res=0;

void dfs(int x,int y)  //遍历0周围所有的点,标记并且将该点设置为不可点击
{
	vis[x][y]=1;
	num[x][y]=-1;
	
	for(int i=0;i<8;i++)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if(nx>=0&&ny>=0&&nx<n&&ny<n) //边界值的判断
		{
			if(!vis[nx][ny]&&num[nx][ny]!=-1)
			{
				if(num[nx][ny]>0) //标记已经遍历
				{
					vis[nx][ny]=1;
					num[nx][ny]=-1;
				}
				if(num[nx][ny]==0) dfs(nx,ny);
			}
		}
	}
}

int main()
{
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		
		scanf("%d",&n);
		for(int j=0;j<n;j++) cin>>m[j];
		
		memset(num,0,sizeof(num)); //每次循环记得清空数组
		
		for(int j=0;j<n;j++)
		{
			for(int k=0;k<n;k++)
			{
				if(m[j][k]!='*') //非雷点统计其8邻域中雷的个数
				{
					for(int d=0;d<8;d++)
					{
						int x=j+dx[d],y=k+dy[d];
						if(x>=0 && x<n && y>=0 && y<n && m[x][y]=='*') //找雷
						{
							num[j][k]++;
						}
					}
				}else{
					num[j][k]=-1; //是雷则标记为-1
				}
				
			}
		}
		
		res=0; //重置res
		memset(vis,0,sizeof(vis)); //重置遍历数组
		
		//找到0的个数
		for(int j=0;j<n;j++){
			for(int k=0;k<n;k++){
				if(num[j][k]==0&&!vis[j][k]){ 
					res++;
					dfs(j,k);
				}
			}
		}
		
		//找漏网之鱼
		for(int j=0;j<n;j++)
		{
			for(int k=0;k<n;k++){
				if(num[j][k]!=-1&&!vis[j][k]) res++;
			}
		}
		printf("Case #%d: %d\n",i,res);
	}
	
	
	return 0;
}

明日预告:网络分析

准备趁着清明节假期啃块硬骨头。

相关推荐
nuo5342026 分钟前
The 2024 ICPC Kunming Invitational Contest
c语言·数据结构·c++·算法
luckilyil7 分钟前
Leetcode 每日一题 11. 盛最多水的容器
算法·leetcode
小王同学的C++11 分钟前
移动语义和拷贝语义有什么区别?
c++
霁月风21 分钟前
设计模式——装饰器模式
c++·设计模式·装饰器模式
叫我龙翔24 分钟前
【项目日记】仿mudou的高并发服务器 --- 实现缓冲区模块,通用类型Any模块,套接字模块
linux·运维·服务器·网络·c++
七侠镇莫尛貝大侠202329 分钟前
C:mbedtls库实现https双向认证连接示例_七侠镇莫尛貝大侠20241122
c语言·开发语言·https
A.A呐37 分钟前
LeetCode 1658.将x减到0的最小操作数
算法·leetcode
hn小菜鸡38 分钟前
LeetCode 144.二叉树的前序遍历
算法·leetcode·职场和发展
rubyw44 分钟前
如何选择聚类算法、回归算法、分类算法?
算法·机器学习·分类·数据挖掘·回归·聚类
编程探索者小陈1 小时前
【优先算法】专题——双指针
数据结构·算法·leetcode