蓝桥杯真题——数字接龙

蓝桥杯2024年第十五届省赛真题-数字接龙

题目描述

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × N 的格子棋盘上展开,其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下:

1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。

2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。

3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。

4. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。

为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图2 所示;因此行进路径可以用一个包含 0 . . . 7 之间的数字字符串表示,如下图 1是一个迷宫示例,它所对应的答案就是:41255214。

蓝桥杯2024年第十五届省赛真题-数字接龙

现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 −1。

输入格式

第一行包含两个整数 N、K。接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。

输出格式

输出一行表示答案。如果存在答案输出路径,否则输出 −1。

样例输入

3 3
0 2 0
1 1 1
2 0 2

样例输出

41255214

提示

【样例说明】行进路径如图 1 所示。
【评测用例规模与约定】对于 80% 的评测用例:1 ≤ N ≤ 5。对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

思路:

注意:这里的字典序最小不是长度最短,是数字最小的意思。

使用DFS深度优先遍历寻找路径(dfs的三个参数分别是当前位置的坐标和该位置的值)

dfs中结束条件是判断值是否符合,并且只要找到一个答案就结

主要部分是通过for循环来遍历8个移动方向,这里要判断移动后的点是否合理 

判断下一个点的函数:判断是否越界、是否已经访问、是否出现路径交叉                                      

判断交叉:

代码:

#include<bits/stdc++.h>
using namespace std;

const int N=20;
int n,k;
int a[N][N];//每格中的值 
bool vis[N][N];//判断是否访问过

int dy[]={0,1,1,1,0,-1,-1,-1};
int dx[]={-1,-1,0,1,1,1,0,-1};
vector<int> path;//记录当前的路径编号
string ans;//最终答案 

bool flag=0;//结束判断条件
//只要找到一个答案就停止遍历,因为本身就是从i从小到大开始遍历
//越往后字典序(数字值)越大,因此只要找到一个答案就停止(防止有一个数据集越界)

//检查是否可以移动到(x,y)位置 
bool check(int x,int y,int dir)//x,y是下一个要访问的点,dir是从哪个方向到x,y(方向数组i的值) 
{
	//检查是否越界 
	if(x<0||x>=n||y<0||y>=n) return false;
	//检查是否已访问
	if(vis[x][y]) return false;
	//对于斜向移动(由分析可知,这时i都是奇数),检查是否有交叉
	if(dir%2!=0)
	{
		//上一个地点坐标 
		int sx=x-dx[dir];
		int sy=y-dy[dir];
		//判断是否交叉 
		if(vis[sx+dx[dir]][sy]&&vis[sx][sy+dy[dir]]) return false;
	}
	return true;
 } 
 
void dfs(int x,int y,int u)//u是当前期望的值0,1,2…k-1 
{
	//如果当前位置的值不等于期望值 ,返回 
	if(a[x][y]!=u) return ;
	//如果已经访问了所有结点并到达终点 
	if(path.size()==n*n-1&&x==n-1&&y==n-1)//结束条件必不可少 
	{
		string s;//置初值 
		for(auto i:path)
			s+=i+'0';
		ans=s;
		flag=1;
		return ;
	}
	//尝试8个方向的移动
	for(int i=0;i<8;i++)
	{
		int tx=x+dx[i];//移动的下一个点
		int ty=y+dy[i];
		if(check(tx,ty,i))//检查下一个点是否合理 
		{
			vis[tx][ty]=1;//标记访问
			path.push_back(i);//加入编号集
			dfs(tx,ty,(u+1)%k);
			path.pop_back();//当条件不符合时恢复现场 
			vis[tx][ty]=0;
			if(flag) return;
		 } 
	 } 
	
	
 } 
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>k;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			cin>>a[i][j];
			
	vis[0][0]=1;//标记起点已被访问
	dfs(0,0,0);//当前点的位置x、y,期望值(0,1,2…k-1 
	
	if(!ans.empty())
		cout<<ans<<endl;
	else
		cout<<"-1"<<endl;

	return 0;
 } 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值