当前位置: 代码迷 >> 综合 >> JakeLin- [蓝桥杯][2016年第七届真题]路径之谜-题解-DFS/回溯法
  详细解决方案

JakeLin- [蓝桥杯][2016年第七届真题]路径之谜-题解-DFS/回溯法

热度:59   发布时间:2023-11-13 15:28:33.0

题目描述

小明冒充X星球的骑士,进入了一个奇怪的城堡。城堡里边什么都没有,只有方形石头铺成的地面。
假设城堡地面是 n x n 个方格。【如上图】所示。按习俗,骑士要从西北角走到东南角。
可以横向或纵向移动,但不能斜着走,也不能跳跃。每走到一个新方格,就要向正北方和正西方各射一箭。
(城堡的西墙和北墙内各有 n 个靶子)
同一个方格只允许经过一次。但不必走完所有的方格。
如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?
有时是可以的,比如图中的例子。
本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

输入

第一行一个整数N(0<N<20),表示地面有 N x N 个方格
第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东)
第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)

输出

一行若干个整数,表示骑士路径。

为了方便表示,我们约定每个小格子用一个数字代表,从西北角开始编号: 0,1,2,3....
比如,图1.png中的方块编号为:
0  1  2  3
4  5  6  7
8  9  10 11
12 13 14 15

样例输入

4
2 4 3 4
4 3 3 3

样例输出

0 4 5 1 2 3 7 11 10 9 13 14 15

原题链接:[蓝桥杯][2016年第七届真题]路径之谜 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 25;
int map[maxn][maxn];   //地图
int to_north[maxn],to_west[maxn];  //目标
int north[maxn],west[maxn];  //统计靶子箭数
int vis[maxn][maxn];  //标记是否访问
int dx[]={0,0,1,-1};  //四个方向
int dy[]={1,-1,0,0};
int n;
vector<int> road; //存储路径,相当于递归中的栈
int res[maxn];
void dfs(int x,int y){//加速作用,若访问此节点靶子箭数超过目标则无需判断if(north[y]+1 > to_north[y] || west[x]+1 > to_west[x]){  return;}north[y]++;west[x]++;vis[x][y]=1;road.push_back(map[x][y]);if(x==n-1 && y==n-1){  //到达终点int tag = 1;for(int i=0;i<n;i++){   //判断靶子是否达到想要的最终状态if(north[i]!=to_north[i] || west[i]!=to_west[i]){tag=0;break;}}if(tag==1){  //符合条件for(int i=0;i<road.size();i++){cout<<road[i]<<" ";}return;}}for(int i=0;i<4;i++){   //遍历四个可达(不越界)方向int newx = x + dx[i];int newy = y + dy[i];if(newx>=0 && newx<n && newy>=0 && newy<n && vis[newx][newy]==0){dfs(newx,newy);}}//回溯,回到上一个点的状态north[y]--;west[x]--;road.pop_back();vis[x][y]=0;    
}
int main(){//初始化cin>>n;for(int i=0;i<n;i++){cin>>to_north[i];}for(int i=0;i<n;i++){cin>>to_west[i];}int cnt=0;for(int i=0;i<n;i++){  //傻傻的做法for(int j=0;j<n;j++){map[i][j]=cnt++;}}    //调用DFS,从(0,0)开始dfs(0,0);return 0;
}