sicily 1153. 马的周游问题
一、题目描述
在一个8 * 8的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线。
为了便于表示一个棋盘,我们按照从上到下,从左到右对棋盘的方格编号,如下所示:
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
马的走法是“日”字形路线,例如当马在位置15的时候,它可以到达2、4、7、11、19、23、26和28。但是规定马是不能跳出棋盘外的,例如从位置1只能到达9和14。
Input
输入有若干行。每行一个整数N(1<=N<=30),表示马的起点。最后一行用-1表示结束,不用处理。
Output
对输入的每一个起点,求一条周游线路。对应地输出一行,有30个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。
Sample Input
4
-1
Sample Output
注意:如果起点和输入给定的不同,重复多次经过同一方格或者有的方格没有被经过,都会被认为是错误的。
二、算法思想及主要数据结构
- 算法思想:这题使用 dfs 来找到一条路径,因为根据题目描述可以看出路径的深度并不会很大,所以采用深搜是一种比较好的方法。使用递归来达到深搜。
- 主要数据结构:这里使用结构体来保存节点内部值,使用 vector 来保存节点。
三、详细解题思路
- 首先因为棋盘的大小变大了,这个时候完全不剪枝的深搜显然会超时。根据树的结构可以知道,减少上层子节点,则下层子节点数也会相应减少。所以这里的一个思路就是保证先走可扩展位置比较少的位置,可扩展就是说如果当前节点是该节点,那么其可以走的下一个节点的数目。所以这里先求得下一个可能走的节点的可扩展位置数,然后根据位置数进行一个排序,优先走位置数较少的位置。
2. 位置处理,因为原棋盘的位置表示是用一个数字来表示的,这样对于我们的操作并不适合,所以将棋盘的代表数字转成一个 8 * 8 数组的下标来处理:
x = (N - 1) / 8;
y = (N - 1) % 8;
3. 马的移动分析:因为马必须走“日”型的路线,所以马的最多移动位置会有 8 个,分别是如下:
position(-1, 2), position(-2, 1), position(-2, -1), position(-1, -2),
position(1, -2), position(2, -1), position(2, 1), position(1, 2)
那么在每次移动后都可能有 8 个位置,需要对这些位置进行有效性判断:
bool isValid(int x, int y) {
return x >= 0 && y >= 0 && x <= 7 && y <= 7;
}
也即位置一定要在棋盘内。
4. 路径记录:因为一定会在 64 步内得到结果,那么也就是说每一步代表一个位置,那么只需要用一个含 64 个元素的数组来记录位置就可以。
int route[64];
在走一条新的路径的时候,只需要将步数对应位置的数字改成对应新位置的数字就可以:
route[step] = 8 * yTemp + xTemp + 1;
5. 在每个当前位置,会取得其可能走的下一个位置,在得到这些位置后再一这些位置为当前节点去看其可能的扩展位置的数目,根据这个数目进行排序,保存在一个vector里面,然后从该 vector 里面找下一个位置即可
if (isValid(xTemp, yTemp)) {
int canMovePoisitionNum = getCanMovePositionNum(xTemp, yTemp);
if (canMovePoisitionNum != 0)
poisition.push_back(Position(xTemp, yTemp, canMovePoisitionNum));
}
sort(poisition.begin(), poisition.end(), cmp);
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector> using namespace std; bool visited[][];
bool success = false;
int roate[]; struct Position{
Position(int x_ = , int y_ = , int num = ): x(x_), y(y_), canMovePoisitionNum(num) { }
int x;
int y;
int canMovePoisitionNum;
}; Position Move[] = {Position(, -), Position(, -), Position(, ), Position(, ),
Position(-, ), Position(-, ), Position(-, -), Position(-, -)}; bool isValid(int x, int y) {
return x >= && y >= && x <= && y <= ;
} int getCanMovePositionNum(int x, int y) {
int canMovePoisitionNum = ;
for (int i = ; i != ; ++i) {
if(isValid(x + Move[i].x, y + Move[i].y))
canMovePoisitionNum++;
}
return canMovePoisitionNum;
} bool cmp(const Position &a, const Position &b) {
return a.canMovePoisitionNum < b.canMovePoisitionNum;
} void search(int step, int x, int y) {
vector<Position> poisition;
for (int i = ; i != ; ++i) {
int xTemp = x + Move[i].x;
int yTemp = y + Move[i].y;
if (isValid(xTemp, yTemp)) {
int canMovePoisitionNum = getCanMovePositionNum(xTemp, yTemp);
if (canMovePoisitionNum != )
poisition.push_back(Position(xTemp, yTemp, canMovePoisitionNum));
}
}
sort(poisition.begin(), poisition.end(), cmp);
for (int i = ; i != poisition.size(); ++i) {
if (success)
return;
if (step == ) {
success = true;
return;
}
if (!visited[poisition[i].x][poisition[i].y]) {
++step;
roate[step] = * poisition[i].x + poisition[i].y + ;
visited[poisition[i].x][poisition[i].y] = true;
search(step, poisition[i].x, poisition[i].y);
visited[poisition[i].x][poisition[i].y] = false;
--step;
}
}
} int main(int argc, char *argv[])
{
int N, x, y;
while (scanf("%d", &N) && N != -) {
roate[] = N;
memset(visited, false, sizeof(visited));
success = false;
x = (N - ) / ;
y = (N - ) % ; visited[x][y] = true;
search(, x, y); for (int i = ; i != ; i++)
printf("%d ", roate[i]);
printf("%d\n", roate[]);
} return ;
}
sicily 1153. 马的周游问题的更多相关文章
- Sicily 1153: 马的周游问题(DFS+剪枝)
这道题没有找到一条回路,所以不能跟1152一样用数组储存后输出.我采用的方法是DFS加剪枝,直接DFS搜索会超时,优化的方法是在搜索是优先走出度小的路径,比如move1和move2都可以走,但是如走了 ...
- Sicily1153-马的周游问题:启发式搜索
代码地址: https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1153.c 题目如下: 1153. 马的周游问题 C ...
- sicily 题目分类
为了方便刷题,直接把分类保存下来方便来找. 转自:http://dengbaoleng.iteye.com/blog/1505083 [数据结构/图论] 1310Right-HeavyTree笛卡尔树 ...
- 【算法】深度优先 马走日 Hamilton routes
在n*m的棋盘中,马只能走“日” 字.马从位置(x,y)处出发,把棋盘的每一格都走一次,且只走一次.找出所有路径. ××××××××××××× 类似问题: 在半个中国象棋棋盘上,马在左下角(1,1)处 ...
- Sicily-1153 解题报告
一.原题中文大意. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
- Java输入输出流进阶
输入输出的内容是文本内容,考虑使用字符流. 输入输出的内容是二进制内容,考虑使用字节流. 凡是能用记事本打开并查看的内容称为文本文件,反之则为二进制文件. package ch15; import j ...
- python之新的开始
Day 1-Morning 终于开通了新的博客(等待审核的过程用着备忘录敲...)~感谢几位大佬们愿意带我一起学习 大家一起加油!(苟富贵,勿相忘!/doge 哈哈哈) 初学python,以下 ...
- Sicily 1151: 简单的马周游问题(DFS)
这道题嘛,直接使用DFS搜索,然后莫名其妙地AC了.后来看了题解,说是move的顺序不同的话可能会导致超时,这时便需要剪枝,真是有趣.原来自己是误打误撞AC了,hhh.题解还有另一种解法是先把一条完整 ...
- 骑士周游问题跳马问题C#实现(附带WPF工程代码)
骑士周游问题,也叫跳马问题. 问题描述: 将马随机放在国际象棋的8×8棋盘的某个方格中,马按走棋规则进行移动.要求每个方格只进入一次,走遍棋盘上全部64个方格. 代码要求: 1,可以任意选定马在棋盘上 ...
随机推荐
- Version
题目 有三个操作: \(change \ u \ v \ a \ b\) : \(u\)到\(v\)路径上的点点权加上\(a+k*b\),\(k\)为第几个点,\(u\)为第0个点. \(query ...
- (转)Ubuntu 12.04 LTS安装VMware Tools实现linux和window 互相复制:无法找到kernel header path的问题
Ubuntu 12.04 LTS安装VMware Tools无法找到kernel header path的问题 ubuntuvmware Ubuntu 12.04 安装 VMware Tools, ...
- ictclas4j 分词工具包 安装流程
首先把 ictclasj解压缩,然后 1.把 Data文件夹整个拷贝到 Eclipse项目的文件夹下, 2.而 bin目录下的 org文件夹整个拷贝到你 Eclipse项目的 bin目录下,(将cla ...
- 【题解】Atcoder ARC#90 F-Number of Digits
Atcoder刷不动的每日一题... 首先注意到一个事实:随着 \(l, r\) 的增大,\(f(r) - f(l)\) 会越来越小.考虑暴力处理出小数据的情况,我们可以发现对于左端点 \(f(l) ...
- 【题解】SHOI2014概率充电器
首先发现答案就是每个节点有电的概率之和.有电的概率牵扯太广不好求,所以转化为求没有电的概率.这题最难的部分在于:一个节点如果有电,可以来自儿子,也可以来自父亲.我们考虑将这两个部分分离开来:建立状态 ...
- 【基础】ASP.net MVC 文件下载的几种方法(欢迎讨论)
在ASP.net MVC 中有几种下载文件的方法 前提:要下载的文件必须是在服务器目录中的,至于不在web项目server目录中的文件下载我不知道,但是还挺想了解的. 第一种:最简单的超链接方法,&l ...
- POJ2891:Strange Way to Express Integers——题解
http://poj.org/problem?id=2891 题目大意: k个不同的正整数a1,a2,...,ak.对于一些非负m,满足除以每个ai(1≤i≤k)得到余数ri.求出最小的m. 输入和输 ...
- BZOJ1823:[JSOI2010]满汉全席——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=1823 https://www.luogu.org/problemnew/show/P4171 题面 ...
- BZOJ4539 [Hnoi2016]树 【倍增 + 主席树】
题目链接 BZOJ4539 题解 我们把每次复制出来的树看做一个点,那么大树实际上也就是一棵\(O(M)\)个点的树 所以我们只需求两遍树上距离: 大树上求距离,进入同一个点后在模板树上再求一次距离 ...
- 笔记-树形dp
this is not a 正经的note you may not understand Problem 1:二叉树,有权,要选它父亲才能选它,$n\leq200,m\leq500$ I: $dp_{ ...