openjudge_2.5基本算法之搜索_1490:A Knight‘s Journey

题目

1490:A Knight's Journey

总时间限制: 1000ms 内存限制: 65536kB

描述

Background

The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey

around the world. Whenever a knight moves, it is two squares in one direction and one square perpendicular to this. The world of a knight is the chessboard he is living on. Our knight lives on a chessboard that has a smaller area than a regular 8 * 8 board, but it is still rectangular. Can you help this adventurous knight to make travel plans?

Problem

Find a path such that the knight visits every square once. The knight can start and end on any square of the board.

输入

The input begins with a positive integer n in the first line. The following lines contain n test cases. Each test case consists of a single line with two positive integers p and q, such that 1 <= p * q <= 26. This represents a p * q chessboard, where p describes how many different square numbers 1, . . . , p exist, q describes how many different square letters exist. These are the first q letters of the Latin alphabet: A, . . .

输出

The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the lexicographically first path that visits all squares of the chessboard with knight moves followed by an empty line. The path should be given on a single line by concatenating the names of the visited squares. Each square name consists of a capital letter followed by a number.

If no such path exist, you should output impossible on a single line.

样例输入

3

1 1

2 3

4 3

样例输出

Scenario #1:

A1

Scenario #2:

impossible

Scenario #3:

A1B3C1A2B4C2A3B1C3A4B2C4

翻译

背景:

骑士厌倦了一遍又一遍地看到同样的黑白方块,决定去旅行在世界各地。

无论何时骑士移动,它都是一个方向上的两个正方形和一个垂直于这个方向的正方形。

骑士的世界就是他生活的棋盘。我们的骑士生活在一个比普通的8 * 8棋盘面积小的棋盘上,

但它仍然是矩形的。你能帮这位爱冒险的骑士制定旅行计划吗?

问题:

找到一条路径,让骑士访问每个方块一次。马可以在棋盘的任何方格上开始和结束。

输入:

输入从第一行的正整数n开始。下面几行包含n个测试用例。

每个测试用例由单行组成,其中包含两个正整数p和q,使得1 <= p * q <= 26。

这表示一个p * q棋盘,其中p表示有多少个不同的平方数1,...p存在,

q表示存在多少个不同的正方形字母。这些是拉丁字母的前q个字母:A,...

输出:

每个场景的输出都以包含"场景#i:"的一行开始,其中i是从1开始的场景的编号。

然后打印一行,其中包含按字典顺序排列的第一个路径,

该路径访问带有骑士移动的棋盘上的所有方格,然后是空行。

路径应该通过连接所访问方块的名称在单行上给出。每个方框名称由一个大写字母后跟一个数字组成。

如果不存在这样的路径,您应该在单行上输出impossible。

理解

在棋盘上走马,每个点只踩一次,能不能踏遍棋盘上每个格子。

如果不能输出:impossible

如果可以,找到按字典序的所有位置,每个位置用对应的表格位置表示(用字母表示列,再是数字表示的行)

后面用空行分开各组。

难点

1.忽视各组间的空行,要仔细审题

2.一个点出发可以去周围的八个点,要优先按字典序选择

3.递归才有回溯,递归能完成(踏遍棋盘)就好,不行就得恢复,就是撤销上一步。

4.每次往周围八个方向走,多层递归。运行前要判断完成没,从而杜绝找到后继续递归。

代码

#include <bits/stdc++.h>

using namespace std;

struct point{

int x,y,n;

bool k;

string s;

point(){

k=0;

}

point(int xx,int yx){

x=xx,y=yx,k=0;n=1;

s="";s+=char('A'+yx-1);s+=char('0'+xx);

}

void set(int xx,int yx){

x=xx,y=yx,k=0;n=1;

s="";s+=char('A'+yx-1); s+=char('0'+xx);

}

}b[30][30];//记住当前点位置和到达步数

int n,p,q,

d[8][2]={//马可以走上下左右8个点,但是得按字典序,就是A12,完了B12,C12等

{-1,-2},{1,-2},//最左侧A列的上下,

{-2,-1},{2,-1},//第二列B列上下

{-2,1},{2,1},//第二列D列上下

{-1,2},{1,2}};//第二列E列上下

bool ans;//标记走过没

vector v;//存遍历路径

bool ok(int x,int y){

return x>=1&&x<=p&&y>=1&&y<=q&&!b[x][y].k;

}

void view(){

cout<<"走到哪步了"<<endl;

for(int i=1;i<=p;i++){

for(int j=1;j<=q;j++)cout<<b[i][j].k<<","<<b[i][j].s<<"\t";

cout<<endl;

}

}

void go(int xx,int yx){

//cout<<xx<<","<<yx<<"="<<b[xx][yx].s<<"步数"<<b[xx][yx].n<<endl;

//view();

if(b[xx][yx].n==p*q){

//cout<<"找到了!!!!!!!!!!!\n";

for(int i=0;i<v.size();i++)cout<<v[i];cout<<endl;

ans=1;

return;//此次退出

}

if(ans)return;//八个方向调用,只要有答案了就退出

for(int i=0;i<8;i++){

int x=xx+d[i][0],y=yx+d[i][1];

if(ok(x,y)){

b[x][y].k=1;b[x][y].n=b[xx][yx].n+1;//标记来过这里,并且记住是第几步

v.push_back(b[x][y].s);

go(x,y);

v.pop_back();//回溯,撤销该步

b[x][y].n=b[xx][yx].n-1;//说明前面得走法不对,要取消步数

b[x][y].k=0;//撤销上步

}

}

}

int main(){

//freopen("data.cpp","r",stdin);

cin>>n;

for(int c=1;c<=n;c++){

cout<<"Scenario #"<<c<<":\n";//\转义符号,不输出字符,而是代表的换行符

ans=0;v.clear();//多组数据初始化

cin>>p>>q;

for(int i=1;i<=p;i++)

for(int j=1;j<=q;j++)b[i][j].set(i,j);//初始化个点位

b[1][1].set(1,1);b[1][1].k=1;v.push_back(b[1][1].s);//标记出发点,并放入路径队列里

go(1,1);//递归深搜每个点,如果达不到就回溯,就是恢复失败的痕迹从别的方向尝试

if(!ans)cout<<"impossible\n";

cout<<endl;

}

return 0;

}

总结

宽搜需要队列,只要非空就继续。

深搜要递归,没找到没找完就得递归,该路不通得撤销上一步。

用vector记录走法。

相关推荐
为何创造硅基生物30 分钟前
C 语言 typedef 结构体私有化
c语言·开发语言·算法
yzx99101333 分钟前
递归算法入门:像俄罗斯套娃一样思考
人工智能·算法
心中有国也有家39 分钟前
从零上手 CANN 学习中心:像逛技术便利店一样学昇腾
学习·算法·开源
oo哦哦1 小时前
搜索矩阵系统的最短路密码:用Dijkstra算法和网络流理论,解释为什么你做了1000个关键词,流量还不如别人30个
网络·算法·矩阵
Matlab程序猿小助手1 小时前
【MATLAB源码-第319期】基于matlab的帝王蝶优化算法(MBO)无人机三维路径规划,输出做短路径图和适应度曲线.
开发语言·算法·matlab
图码1 小时前
二分查找进阶:如何在有序数组中快速找到Upper Bound?
数据结构·算法·面试·分类·柔性数组
试剂界的爱马仕1 小时前
《古董局·终局5:潮生》第 2 章:镜子的天赋
大数据·人工智能·算法
Cthy_hy1 小时前
树状数组(BIT)进阶:差分优化实现区间修改、区间查询
数据结构·python·算法
YsyaaabB2 小时前
ACM 模式通用代码模板
java·c++·python·算法
ComputerInBook2 小时前
Euclid 几何变换——仿射(affine)变换
算法·仿射变换·几何变换