经验大分享:Sicily1153

简介: 经验大分享:Sicily1153

代码地址:

题目如下:

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):

1 // Problem#: 1153

2 // Submission#: 3914599

3 // The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

4 // URI:

5 // All Copyright reserved by Informatic Lab of Sun Yat-sen University

6 #include

7 #include

8

9 bool visited【8】【8】;

10 int y_direction【8】 = {-2, -2, -1, -1, 1, 1, 2, 2};

11 int x_direction【8】 = {-1, 1, 2, -2, 2, -2, -1, 1};

12 int record【64】;

13 bool found;

14

15 inline bool is_valid(int x, int y) {

16 return x >= 0 x < 8 y >= 0 y < 8;

17 }

18

19 inline int get_number(int x, int y) {

20 return x 8 + y + 1;

21 }

22

23 void dfs(int x, int y, int step) {

24 if (visited【x】【y】 || found)

25 return;

26 visited【x】【y】 = true;

27 record【step】 = get_number(x, y);

28 if (step == 63) {

29 found = true;

30 return;

31 }

32 int temp_x, temp_y;

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

34 temp_x = x + x_direction【i】, temp_y = y + y_direction【i】;

35 if (is_valid(temp_x, temp_y) !visited【temp_x】【temp_y】)

36 dfs(temp_x, temp_y, step + 1);

37 }//代码效果参考:http://www.ezhiqi.com/zx/art_822.html

38 visited【x】【y】 = false;

39 }

40

41 int main() {

42 int n;

43 while (scanf("%d", n) n != -1) {

44 found = false;

45 memset(visited, 0, sizeof(visited));

46 dfs((n - 1) / 8, (n - 1) % 8, 0);

47 for (int i = 0; i < 63; i++)

48 printf("%d ", record【i】);

49 printf("%d\n", record【63】);

50 }

51 return 0;

52 }

怎么优化?

答案是: 启发式搜索。

启发式搜索其实很简单,就是在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】

好,尝试一下,在延伸树的支点的时候对每个支点加权排序之后再遍历。

代码如下:

1 #include

2 #include

3 #include

4 #include

5

6 bool visited【8】【8】;

7 int y_direction【8】 = {-2, -2, -1, -1, 1, 1, 2, 2};

8 int x_direction【8】 = {-1, 1, 2, -2, 2, -2, -1, 1};

9 int record【64】;

10 bool found;

11

12 struct Node {

13 int x, y, weight;

14 Node(int x, int y, int weight) {

15 this->x = x;

16 this->y = y;

17 this->weight = weight;

18 }

19 bool operator<(const Node node) const {

20 return weight [span style="color: rgba(0, 0, 0, 1)"> node.weight;

21 }

22 };

23

24 inline bool is_valid(int x, int y) {

25 return x >= 0 x < 8 y >= 0 y < 8;

26 }

27

28 inline int get_number(int x, int y) {

29 return x * 8 + y + 1;

30 }

31

32 inline int get_weight(int x, int y) {

33 int temp_x, temp_y, weight = 0;

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

35 temp_x = x + x_direction【i】, temp_y = y + y_direction【i】;

36 if (is_valid(temp_x, temp_y) !visited【temp_x】【temp_y】)

37 weight++;

38 }

39 return weight;

40 }

41

42 void dfs(int x, int y, int step) {

43 if (visited【x】【y】 || found)

44 return;

45 visited【x】【y】 = true;

46 record【step】 = get_number(x, y);

47 if (step == 63) {

48 found = true;

49 return;

50 }

51 int temp_x, temp_y;

52 std::vector v;

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

54 temp_x = x + x_direction【i】, temp_y = y + y_direction【i】;

55 if (is_valid(temp_x, temp_y) !visited【temp_x】【temp_y】)

56 v.push_back(Node(temp_x, temp_y, get_weight(temp_x, temp_y)));

57 }

58 std::sort(v.begin(), v.end());

59 for (int i = 0; (size_t)i < v.size(); i++)

60 dfs(v【i】.x, v【i】.y, step + 1);

61 visited【x】【y】 = false;

62 }

63

64 int main() {

65 int n;

66 while (scanf("%d", n) n != -1) {

67 found = false;

68 memset(visited, 0, sizeof(visited));

69 dfs((n - 1) / 8, (n - 1) % 8, 0);

70 for (int i = 0; i < 63; i++)

71 printf("%d ", record【i】);

72 printf("%d\n", record【63】);

73 }

74 return 0;

75 }

运用此策略惊人的达到了0.00s,在性能的提升上我确实没想到能提升这么多。

以下为两个版本代码提交截图:

相关文章
|
5月前
|
JSON 前端开发 数据格式
经验大分享:TheGeneofBitizens
经验大分享:TheGeneofBitizens
32 3
|
5月前
经验大分享:OpenFOAM中的边界条件(一)
经验大分享:OpenFOAM中的边界条件(一)
199 0
经验大分享:OpenFOAM中的边界条件(一)
|
5月前
经验大分享:sdfdsf
经验大分享:sdfdsf
25 0
|
5月前
|
JSON 网络协议 Linux
经验大分享:serval
经验大分享:serval
23 0
|
5月前
|
图形学
技术经验解读:【学习笔记】恶梦射手NightmaresShooter(一)
技术经验解读:【学习笔记】恶梦射手NightmaresShooter(一)
86 0
|
6月前
|
安全 前端开发 开发者
干货!6个方面,32条总结教你提升职场经验
本文提出了职场成长的建议,包括不要依赖“新人”身份,撰写技术博客促进成长,阅读《金字塔原理》和《高效能人士的七个习惯》等书籍,积极解决问题,不沉迷于忙碌,长远看待得失,拓宽知识领域,保持好奇和热爱。日常工作要注重质量,主动规划,良好沟通,避免传播负面情绪,理解和尊重上级,学会被管理。培养定义问题的能力,以价值、结果和问题为导向思考,控制情绪,以及成为他人的追随者而非仅仅管理者。
|
测试技术 Linux Go
|
小程序 程序员 Windows
学习经验
写写自己的学习经验
|
存储 算法 Ubuntu
学习 C++ 的一点浅薄经验
工作所需,需要学习下 C++,今天就谈一下自己是怎么快速学习 C++,并且在工作中实际上手开发的,希望能够给大家一些启发。
162 0