Sicily1153-马的周游问题:启发式搜索
代码地址: https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1153.c
题目如下:
1153. 马的周游问题
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge
Description
和题目C同样的任务,这里只是把棋盘扩大到标准的国际象棋。对这样一个8 * 8的棋盘用同样的方法编号如下:
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
Input
输入有若干行。每行一个整数N(1<=N<=64),表示马的起点。最后一行用-1表示结束,不用处理。
Output
对输入的每一个起点,求一条周游线路。对应地输出一行,有64个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。
典型的搜索问题,1152数据规模较小,直接DFS就可以过,然而1153不行,以下为超时代码(>0.99s):
// Problem#: 1153
// Submission#: 3914599
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>
#include <cstring> bool visited[][];
int y_direction[] = {-, -, -, -, , , , };
int x_direction[] = {-, , , -, , -, -, };
int record[];
bool found; inline bool is_valid(int x, int y) {
return x >= && x < && y >= && y < ;
} inline int get_number(int x, int y) {
return x * + y + ;
} void dfs(int x, int y, int step) {
if (visited[x][y] || found)
return;
visited[x][y] = true;
record[step] = get_number(x, y);
if (step == ) {
found = true;
return;
}
int temp_x, temp_y;
for (int i = ; i < ; i++) {
temp_x = x + x_direction[i], temp_y = y + y_direction[i];
if (is_valid(temp_x, temp_y) && !visited[temp_x][temp_y])
dfs(temp_x, temp_y, step + );
}
visited[x][y] = false;
} int main() {
int n;
while (scanf("%d", &n) && n != -) {
found = false;
memset(visited, , sizeof(visited));
dfs((n - ) / , (n - ) % , );
for (int i = ; i < ; i++)
printf("%d ", record[i]);
printf("%d\n", record[]);
}
return ;
}
怎么优化?
答案是: 启发式搜索。
启发式搜索其实很简单,就是在DFS的时候正常情况下是按照固定的顺序对树的节点进行访问的(例如从左到右)。
而启发式搜索则是在DFS搜索的时候对树节点的访问加入一个贪心策略,让每次往下搜索的顺序是有策略性的,有启发性的。(这个贪心策略是为了指向最终的终点)。
那么在马周游问题里面怎么在DFS里面加入这个贪心策略使这个搜索更聪明呢?(更快找到终点)
之前Wansdorff在1823年给出了这个启发策略。
Warnsdorff's rule
Warnsdorf's rule is a heuristic for finding a knight's tour. We move the knight so that we always proceed to the square from which the knight will have the fewest onward moves. When calculating the number of onward moves for each candidate square, we do not count moves that revisit any square already visited. It is, of course, possible to have two or more choices for which the number of onward moves is equal; there are various methods for breaking such ties, including one devised by Pohl [14] and another by Squirrel and Cull.[15]
好,尝试一下,在延伸树的支点的时候对每个支点加权排序之后再遍历。
代码如下:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm> bool visited[][];
int y_direction[] = {-, -, -, -, , , , };
int x_direction[] = {-, , , -, , -, -, };
int record[];
bool found; struct Node {
int x, y, weight;
Node(int x, int y, int weight) {
this->x = x;
this->y = y;
this->weight = weight;
}
bool operator<(const Node &node) const {
return weight < node.weight;
}
}; inline bool is_valid(int x, int y) {
return x >= && x < && y >= && y < ;
} inline int get_number(int x, int y) {
return x * + y + ;
} inline int get_weight(int x, int y) {
int temp_x, temp_y, weight = ;
for (int i = ; i < ; i++) {
temp_x = x + x_direction[i], temp_y = y + y_direction[i];
if (is_valid(temp_x, temp_y) && !visited[temp_x][temp_y])
weight++;
}
return weight;
} void dfs(int x, int y, int step) {
if (visited[x][y] || found)
return;
visited[x][y] = true;
record[step] = get_number(x, y);
if (step == ) {
found = true;
return;
}
int temp_x, temp_y;
std::vector<Node> v;
for (int i = ; i < ; i++) {
temp_x = x + x_direction[i], temp_y = y + y_direction[i];
if (is_valid(temp_x, temp_y) && !visited[temp_x][temp_y])
v.push_back(Node(temp_x, temp_y, get_weight(temp_x, temp_y)));
}
std::sort(v.begin(), v.end());
for (int i = ; (size_t)i < v.size(); i++)
dfs(v[i].x, v[i].y, step + );
visited[x][y] = false;
} int main() {
int n;
while (scanf("%d", &n) && n != -) {
found = false;
memset(visited, , sizeof(visited));
dfs((n - ) / , (n - ) % , );
for (int i = ; i < ; i++)
printf("%d ", record[i]);
printf("%d\n", record[]);
}
return ;
}
运用此策略惊人的达到了0.00s,在性能的提升上我确实没想到能提升这么多。
以下为两个版本代码提交截图:

Sicily1153-马的周游问题:启发式搜索的更多相关文章
- sicily 1153. 马的周游问题
一.题目描述 在一个8 * 8的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线. 为了便 ...
- Sicily 1153: 马的周游问题(DFS+剪枝)
这道题没有找到一条回路,所以不能跟1152一样用数组储存后输出.我采用的方法是DFS加剪枝,直接DFS搜索会超时,优化的方法是在搜索是优先走出度小的路径,比如move1和move2都可以走,但是如走了 ...
- Sicily-1153 解题报告
一.原题中文大意. 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
- 【算法】深度优先 马走日 Hamilton routes
在n*m的棋盘中,马只能走“日” 字.马从位置(x,y)处出发,把棋盘的每一格都走一次,且只走一次.找出所有路径. ××××××××××××× 类似问题: 在半个中国象棋棋盘上,马在左下角(1,1)处 ...
- Java输入输出流进阶
输入输出的内容是文本内容,考虑使用字符流. 输入输出的内容是二进制内容,考虑使用字节流. 凡是能用记事本打开并查看的内容称为文本文件,反之则为二进制文件. package ch15; import j ...
- python之新的开始
Day 1-Morning 终于开通了新的博客(等待审核的过程用着备忘录敲...)~感谢几位大佬们愿意带我一起学习 大家一起加油!(苟富贵,勿相忘!/doge 哈哈哈) 初学python,以下 ...
- Sicily 1151: 简单的马周游问题(DFS)
这道题嘛,直接使用DFS搜索,然后莫名其妙地AC了.后来看了题解,说是move的顺序不同的话可能会导致超时,这时便需要剪枝,真是有趣.原来自己是误打误撞AC了,hhh.题解还有另一种解法是先把一条完整 ...
- PGM学习之七 MRF,马尔科夫随机场
之前自己做实验也用过MRF(Markov Random Filed,马尔科夫随机场),基本原理理解,但是很多细节的地方都不求甚解.恰好趁学习PGM的时间,整理一下在机器视觉与图像分析领域的MRF的相关 ...
- 骑士周游问题跳马问题C#实现(附带WPF工程代码)
骑士周游问题,也叫跳马问题. 问题描述: 将马随机放在国际象棋的8×8棋盘的某个方格中,马按走棋规则进行移动.要求每个方格只进入一次,走遍棋盘上全部64个方格. 代码要求: 1,可以任意选定马在棋盘上 ...
随机推荐
- JavaScript 快速入门回顾
数据类型Number JavaScript不区分整数和浮点数,统一用Number表示,以下都是合法的Number类型: 123; // 整数123 0.456; // 浮点数0.456 1.2345e ...
- C++ 类访问控制(public/protected/private)
第一:private, public, protected 访问标号的访问范围. private:只能由1.该类中的函数.2.其友元函数访问. 不能被任何其他访问,该类的对象也不能访问. protec ...
- CSS3—CSS3和现代Web设计
1.1 现代Web设计理念 1.1.1 可访问性第一 同样一段内容, 可以用成千上万的方法为其设计样式, 但全世界的用户应该依然可以访问它们, 不管他们用什么方式去访问Web——无论手机.键盘控制器还 ...
- [Machine Learning] 梯度下降(BGD)、随机梯度下降(SGD)、Mini-batch Gradient Descent、带Mini-batch的SGD
一.回归函数及目标函数 以均方误差作为目标函数(损失函数),目的是使其值最小化,用于优化上式. 二.优化方式(Gradient Descent) 1.最速梯度下降法 也叫批量梯度下降法Batch Gr ...
- R 语言DataFrame 排序
Sort:dd <- data.frame(b = factor(c("Hi","Med","Hi","Low") ...
- 桂电在线_微信公众平台开发之-运用angularjs显示学校公告新闻列表和详情页面
折腾angularjs的感悟 几天折腾,总的来说看了很多博客,要么不是最新的技术文档,要么写得不够完整,因为别人是基于他们的理解写的技术博客代码不一定会贴完整,所以一旦你用的是最新的想要看完整的实例就 ...
- JS判断浏览器类型以及版本号
<script type="text/javascript"> (function(){ window.nav={}; ...
- JS+CSS实现选项卡功能
[小小一记] 首先我们写一个选项卡的结构出来,包括tab和content: 首先是tab: <ul class="ttitle-box-tabs" id="tabs ...
- Object之克隆对象clone 和__clone()函数
在前面的PHP面向对象之对象和引用,"$b=$a"的方式复制对象传递的是对象的地址,而不是传递对象的值(内容),我们可以通过克隆对象来实现对对象的内容和引用的复制 使用传址引用的方 ...
- www.nygwkt.com
南京宁阳制冷设备维修有限公司是专业从事厨房空调,http://www.nygwkt.com岗位空调制冷设备设计.制造.安装.改造.维修.保养的专业化公司.在南京享有很高的客户评论. 我们对南京宁阳制冷 ...