代码地址: 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-马的周游问题:启发式搜索的更多相关文章

  1. sicily 1153. 马的周游问题

    一.题目描述 在一个8 * 8的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线. 为了便 ...

  2. Sicily 1153: 马的周游问题(DFS+剪枝)

    这道题没有找到一条回路,所以不能跟1152一样用数组储存后输出.我采用的方法是DFS加剪枝,直接DFS搜索会超时,优化的方法是在搜索是优先走出度小的路径,比如move1和move2都可以走,但是如走了 ...

  3. Sicily-1153 解题报告

    一.原题中文大意. 1      2       3      4       5      6         7     8 9     10       11    12      13    ...

  4. 【算法】深度优先 马走日 Hamilton routes

    在n*m的棋盘中,马只能走“日” 字.马从位置(x,y)处出发,把棋盘的每一格都走一次,且只走一次.找出所有路径. ××××××××××××× 类似问题: 在半个中国象棋棋盘上,马在左下角(1,1)处 ...

  5. Java输入输出流进阶

    输入输出的内容是文本内容,考虑使用字符流. 输入输出的内容是二进制内容,考虑使用字节流. 凡是能用记事本打开并查看的内容称为文本文件,反之则为二进制文件. package ch15; import j ...

  6. python之新的开始

    Day 1-Morning     终于开通了新的博客(等待审核的过程用着备忘录敲...)~感谢几位大佬们愿意带我一起学习 大家一起加油!(苟富贵,勿相忘!/doge 哈哈哈) 初学python,以下 ...

  7. Sicily 1151: 简单的马周游问题(DFS)

    这道题嘛,直接使用DFS搜索,然后莫名其妙地AC了.后来看了题解,说是move的顺序不同的话可能会导致超时,这时便需要剪枝,真是有趣.原来自己是误打误撞AC了,hhh.题解还有另一种解法是先把一条完整 ...

  8. PGM学习之七 MRF,马尔科夫随机场

    之前自己做实验也用过MRF(Markov Random Filed,马尔科夫随机场),基本原理理解,但是很多细节的地方都不求甚解.恰好趁学习PGM的时间,整理一下在机器视觉与图像分析领域的MRF的相关 ...

  9. 骑士周游问题跳马问题C#实现(附带WPF工程代码)

    骑士周游问题,也叫跳马问题. 问题描述: 将马随机放在国际象棋的8×8棋盘的某个方格中,马按走棋规则进行移动.要求每个方格只进入一次,走遍棋盘上全部64个方格. 代码要求: 1,可以任意选定马在棋盘上 ...

随机推荐

  1. 使用正则表达式统计vs项目代码总行数[转]

    怎么统计VS2008中工程的总共代码行数?怎么统计VS2008中工程的总共代码行数?在一个大工程中有很多的源文件和头文件,我如何快速统计总行数? ------解决方案----------------- ...

  2. xcode 7种使用coredata遇到 Class not found, using default NSManagedObject instead.问题

    CoreData: warning: Unable to load class named 'CoreDataSwift2_2.Bowtie' for entity 'Bowtie'. Class n ...

  3. NSdate 时间格式

    NSdate 时间格式 NSTimeInterval 时间间隔 基本单位 秒 NSDateFormatter 时间格式器 用于日期对象的格式化或字符串解析为日期对象 日期格式如下: y  年 M  年 ...

  4. Codevs 1337 银行里的迷宫

    1337 银行里的迷宫 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 传送门 题目描述 Description 楚楚每一次都在你的帮助下过了一关又一关(比如他开 ...

  5. 【清橙A1084】【FFT】快速傅里叶变换

    问题描述 离散傅立叶变换在信号处理中扮演者重要的角色.利用傅立叶变换,可以实现信号在时域和频域之间的转换. 对于一个给定的长度为n=2m (m为整数) 的复数序列X0, X1, …, Xn-1,离散傅 ...

  6. WinSock 异步I/O模型 转载

    如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的.Windows操作系统提供了五种I/O模型,分别是: ■ 选择(select):■ 异步选择(WSAAsyncSelect) ...

  7. 关于反射Assembly.Load("程序集").CreateInstance("命名空间.类")

    关于反射Assembly.Load("程序集").CreateInstance("命名空间.类") 而不管在哪一层写这段代码其中的("程序集" ...

  8. android按行读取文件内容的几个方法

    一.简单版 import java.io.FileInputStream; void readFileOnLine(){ String strFileName = "Filename.txt ...

  9. phpcms安装完成后总是跳转到install/install.php

       很多人在本地安装phpcms后总是跳转到install/install.php.由于很多人是第一次使用phpcms,不知道为何会出现这个错误.出现这个大都是phpcms的缓存所致. 如何解决ph ...

  10. python【第十四篇】HTML与CSS初遇

    概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他,这样就可以让浏览器 ...