跳马问题(骑士周游问题)初探

跳马问题(骑士周游问题)初探

2007-09-10 16:00
6253人阅读
评论(11)
收藏
举报
算法
date
file
出版
优化

跳马问题也称为骑士周游问题,是算法设计中的经典问题。其一般的问题描述是:

考虑国际象棋棋盘上某个位置的一只马,它是否可能只走63步,正好走过除起点外的其他63个位置各一次?如果有一种这样的走法,则称所走的这条路线为一条马的周游路线。试设计一个算法找出这样一条马的周游路线。

此题实际上是一个汉密尔顿通路问题,可以描述为:

在一个8×8的方格棋盘中,按照国际象棋中马的行走规则从棋盘上的某一方格出发,开始在棋盘上周游,如果能不重复地走遍棋盘上的每一个方格,
这样的一条周游路线在数学上被称为国际象棋盘上马的哈密尔顿链。请你设计一个程序,从键盘输入一个起始方格的坐标,由计算机自动寻找并打印
出国际象棋盘上马的哈密尔顿链。

能够想到的思路是用回溯,马在每一个点最多有8种跳法,遍历所有这8种可能的跳法即可得到结果。这是回溯算法中的子集树的类型,与典型的子集树问题类型不同的是,这里每一枝有8种可能的选择,而典型的子集树问题只有0,1两种选择。

下面是该算法的实现:

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
/**/
/*
《跳马问题(骑士周游问题)初探》 * File: KnightTravel1.cpp
《跳马问题(骑士周游问题)初探》 * Author: eshow
《跳马问题(骑士周游问题)初探》 * Date: 2007-09-10
《跳马问题(骑士周游问题)初探》 * Question:
《跳马问题(骑士周游问题)初探》 考虑国际象棋棋盘上某个位置的一只马,它是否可能只走63步,正好走过除起点外的其他63个位置各一次?如果有一种这样的走法,则称所走的这条路线为一条马的周游路线。试设计一个算法找出这样一条马的周游路线。
《跳马问题(骑士周游问题)初探》 * Solution:
《跳马问题(骑士周游问题)初探》 使用回溯法,马每一步至多有8种跳法,遍历这8种跳法,得到结果。这是一个子集树的回溯问题,每一个step[i]都在[0, 7]之间。设棋盘大小为N * N,则时间复杂度为O(8^(N * N)),当N = 8时,算法很慢。
《跳马问题(骑士周游问题)初探》
*/


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》#include

<
stdio.h
>

《跳马问题(骑士周游问题)初探》#include

<
stdlib.h
>

《跳马问题(骑士周游问题)初探》#include

<
memory.h
>

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

const

int
N
=

8
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
step[N
*
N]
=


{1}
;
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
chess[N][N]
=


{0}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
Jump[
8
][
2
]
=


{{2,1},{1,2},{1,2},{2,1},{2,1},{1,2},{1,2},{2,1}}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
p
=

0
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
canJump(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (x >= 0&& x < N && y>= 0&& y < N && chess[x][y]== 0)
《跳马问题(骑士周游问题)初探》
return 1;
《跳马问题(骑士周游问题)初探》
return 0;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

void
BackTrace(
int
t,
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (t >= N * N)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 p
++;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
for (int i= 1; i<= N * N 1; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 printf(
%d, step[i]);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< N; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
for (int j= 0; j< N; ++j)
《跳马问题(骑士周游问题)初探》 printf(
%2d, chess[i][j]);
《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》 exit(
1);
《跳马问题(骑士周游问题)初探》
//return;
《跳马问题(骑士周游问题)初探》
}

《跳马问题(骑士周游问题)初探》
else
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< 8;++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (canJump(x+ Jump[i][0], y+ Jump[i][1]))
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 x
+= Jump[i][0];
《跳马问题(骑士周游问题)初探》 y
+= Jump[i][1];
《跳马问题(骑士周游问题)初探》 chess[x][y]
= t + 1;
《跳马问题(骑士周游问题)初探》 step[t]
= i;
《跳马问题(骑士周游问题)初探》 BackTrace(t
+ 1, x, y);
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 0;
《跳马问题(骑士周游问题)初探》 x
-= Jump[i][0];
《跳马问题(骑士周游问题)初探》 y
-= Jump[i][1];
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
main()
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
int x = 0;
《跳马问题(骑士周游问题)初探》
int y = 0;
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 1;
《跳马问题(骑士周游问题)初探》 BackTrace(
1, x, y);
《跳马问题(骑士周游问题)初探》 printf(
All Results Number = %d, p);
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

上述简单回溯算法的时间复杂度是O(8^(N * N)),因为每次都按照Jump定义的顺序遍历,因此在算某些点的时候会很慢。

可以考虑采用启发式的遍历规则:即向前看两步,当每准备跳一步时,设准备跳到(x, y)点,计算(x, y)这一点可能往几个方向跳(即向前看两步),将这个数目设为(x, y)点的权值,将所 有可能的(x, y)按权值排序,从最小的开始,循环遍历所有可能的(x, y),回溯求出结果。算法可以求出所有可能的马跳棋盘路径,算出一个可行 的结果很快,但在要算出所有可能结果时,仍然很慢,因为时间复杂度本质上并没有改变,仍为O(8^(N * N))。下面是实现这一思想的代码:

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
/**/
/*
《跳马问题(骑士周游问题)初探》 * File: KnightTravel2.cpp
《跳马问题(骑士周游问题)初探》 * Author: eshow
《跳马问题(骑士周游问题)初探》 * Date: 2007-09-10
《跳马问题(骑士周游问题)初探》 * Question:
《跳马问题(骑士周游问题)初探》 考虑国际象棋棋盘上某个位置的一只马,它是否可能只走63步,正好走过除起点外的其他63个位置各一次?如果有一种这样的走法,则称所走的这条路线为一条马的周游路线。试设计一个算法找出这样一条马的周游路线。
《跳马问题(骑士周游问题)初探》 * Solution:
《跳马问题(骑士周游问题)初探》 使用回溯法,马每一步至多有8种跳法,遍历这8种跳法,得到结果。这是一个子集树的回溯问题,每一个step[i]都在[0, 7]之间。设棋盘大小为N * N,则时间复杂度为O(8^(N * N)),当N = 8时,算法很慢。
《跳马问题(骑士周游问题)初探》 优化:当每准备跳一步时,设准备跳到(x, y)点,计算(x, y)这一点可能往几个方向跳(即向前看两步),将这个数目设为(x, y)点的权值,将所 有可能的(x, y)按权值排序,从最小的开始,循环遍历所有可能的(x, y),回溯求出结果。算法可以求出所有可能的马跳棋盘路径,算出一个可行 的结果很快,但当N = 8时,要计算所有可能的结果仍然很慢,原因是结果太多了。BackTrace()函数实现了这种思想。
《跳马问题(骑士周游问题)初探》
*/


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》#include

<
stdio.h
>

《跳马问题(骑士周游问题)初探》#include

<
stdlib.h
>

《跳马问题(骑士周游问题)初探》#include

<
memory.h
>

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

const

int
N
=

8
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
step[N
*
N]
=


{1}
;
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
chess[N][N]
=


{0}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
Jump[
8
][
2
]
=


{{2,1},{1,2},{1,2},{2,1},{2,1},{1,2},{1,2},{2,1}}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
p
=

0
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
canJump(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (x >= 0&& x < N && y>= 0&& y < N && chess[x][y]== 0)
《跳马问题(骑士周游问题)初探》
return 1;
《跳马问题(骑士周游问题)初探》
return 0;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
weightStep(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
int count = 0;
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< 8;++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (canJump(x+ Jump[i][0], y+ Jump[i][1]))
《跳马问题(骑士周游问题)初探》 count
++;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
return count;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

void
inssort(
int
a[],
int
b[],
int
n)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (n <= 0)return;
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< n; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
for (int j= i; j > 0;j)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (a[j] < a[j 1])
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
int temp = a[j 1];
《跳马问题(骑士周游问题)初探》 a[j
1]= a[j];
《跳马问题(骑士周游问题)初探》 a[j]
= temp;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 temp
= b[j 1];
《跳马问题(骑士周游问题)初探》 b[j
1]= b[j];
《跳马问题(骑士周游问题)初探》 b[j]
= temp;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

void
BackTrace(
int
t,
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (t >= N * N)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 p
++;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
for (int i= 1; i<= N * N 1; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 printf(
%d, step[i]);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< N; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
for (int j= 0; j< N; ++j)
《跳马问题(骑士周游问题)初探》 printf(
%2d, chess[i][j]);
《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》 exit(
1);
《跳马问题(骑士周游问题)初探》
//return;
《跳马问题(骑士周游问题)初探》
}

《跳马问题(骑士周游问题)初探》
else
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
int count[8], possibleSteps[8];
《跳马问题(骑士周游问题)初探》
int k = 0;
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< 8;++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (canJump(x+ Jump[i][0], y+ Jump[i][1]))
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 count[k]
= weightStep(x+ Jump[i][0], y+ Jump[i][1]);
《跳马问题(骑士周游问题)初探》 possibleSteps[k
++]= i;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 inssort(count, possibleSteps, k);
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< k; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
int d = possibleSteps[i];
《跳马问题(骑士周游问题)初探》 x
+= Jump[d][0];
《跳马问题(骑士周游问题)初探》 y
+= Jump[d][1];
《跳马问题(骑士周游问题)初探》 chess[x][y]
= t + 1;
《跳马问题(骑士周游问题)初探》 step[t]
= d;
《跳马问题(骑士周游问题)初探》 BackTrace(t
+ 1, x, y);
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 0;
《跳马问题(骑士周游问题)初探》 x
-= Jump[d][0];
《跳马问题(骑士周游问题)初探》 y
-= Jump[d][1];
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
main()
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
int x = 0;
《跳马问题(骑士周游问题)初探》
int y = 0;
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 1;
《跳马问题(骑士周游问题)初探》 BackTrace(
1, x, y);
《跳马问题(骑士周游问题)初探》 printf(
All Results Number = %d, p);
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

另外,在查阅和搜索骑士问题的资料时,看到很多朋友说可以使用贪心算法,现在做一个验证看贪心法到底对不对:在只需要一个可行结果时,用贪心算法来替代回溯算法,对KnightTravel2稍做一下修改,在每次选择下一步时都贪心的选择权值最小的那一步,这样就省去了回溯的递归,算法复杂度为O(N * N)的线性时间。代码如下:

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
/**/
/*
《跳马问题(骑士周游问题)初探》 * File: KnightTravel3.cpp
《跳马问题(骑士周游问题)初探》 * Author: eshow
《跳马问题(骑士周游问题)初探》 * Date: 2007-09-10
《跳马问题(骑士周游问题)初探》 * Question:
《跳马问题(骑士周游问题)初探》 考虑国际象棋棋盘上某个位置的一只马,它是否可能只走63步,正好走过除起点外的其他63个位置各一次?如果有一种这样的走法,则称所走的这条路线为一条马的周游路线。试设计一个算法找出这样一条马的周游路线。
《跳马问题(骑士周游问题)初探》 * Solution:
《跳马问题(骑士周游问题)初探》 如果不要求找出所有结果,可以使用贪心算法,在(x, y)的选择时,永远只选择权值最小的那一个跳。就可以很快找到一个结果。travel()函数实现了这种思想。但为何贪心选择可以算出结果有待证明:是一定可以算出,还是可能性很大?验证N = 8的棋盘遍历所有可能的起始点,用贪心法在 x = 5, y = 3时解不出结果,而用回溯遍历所有可能则可以得出结果。因此贪心法解该问题是不正确的。
《跳马问题(骑士周游问题)初探》
*/


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》#include

<
stdio.h
>

《跳马问题(骑士周游问题)初探》#include

<
stdlib.h
>

《跳马问题(骑士周游问题)初探》#include

<
memory.h
>

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

const

int
N
=

8
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
step[N
*
N]
=


{1}
;
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
chess[N][N]
=


{0}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》

int
Jump[
8
][
2
]
=


{{2,1},{1,2},{1,2},{2,1},{2,1},{1,2},{1,2},{2,1}}
;
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
canJump(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (x >= 0&& x < N && y>= 0&& y < N && chess[x][y]== 0)
《跳马问题(骑士周游问题)初探》
return 1;
《跳马问题(骑士周游问题)初探》
return 0;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
weightStep(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
int count = 0;
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< 8;++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (canJump(x+ Jump[i][0], y+ Jump[i][1]))
《跳马问题(骑士周游问题)初探》 count
++;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
return count;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

//
a是要排序的数组,b是a中的步子的索引,用于贪心选择

《跳马问题(骑士周游问题)初探》

int
getMin(
int
a[],
int
b[],
int
n)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
if (n <= 0)1;
《跳马问题(骑士周游问题)初探》
int min = a[0];
《跳马问题(骑士周游问题)初探》
int stepIndex= b[0];
《跳马问题(骑士周游问题)初探》
for (int i= 1; i< n; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (min > a[i])
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 min
= a[i];
《跳马问题(骑士周游问题)初探》 stepIndex
= b[i];
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
return stepIndex;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

bool
travel(
int
x,
int
y)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 1;
《跳马问题(骑士周游问题)初探》
int x0 = x, y0 = y;
《跳马问题(骑士周游问题)初探》
for (int s= 1; s< N * N; ++s)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
int count[8], possibleSteps[8];
《跳马问题(骑士周游问题)初探》
int k = 0;
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< 8;++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
if (canJump(x+ Jump[i][0], y+ Jump[i][1]))
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 count[k]
= weightStep(x+ Jump[i][0], y+ Jump[i][1]);
《跳马问题(骑士周游问题)初探》 possibleSteps[k
++]= i;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
if (k > 0)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
int d = getMin(count, possibleSteps, k);
《跳马问题(骑士周游问题)初探》 x
+= Jump[d][0];
《跳马问题(骑士周游问题)初探》 y
+= Jump[d][1];
《跳马问题(骑士周游问题)初探》 chess[x][y]
= s + 1;
《跳马问题(骑士周游问题)初探》 step[s]
= d;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
else
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 printf(
Start at %d, %d can NOT travel the chess., x0, y0);
《跳马问题(骑士周游问题)初探》
return false;
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》 printf(
Start at %d, %d can travel the chess:, x0, y0);
《跳马问题(骑士周游问题)初探》
for (int i= 1; i<= N * N 1; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》 printf(
%d, step[i]);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》
for (int i= 0; i< N; ++i)
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》
{
《跳马问题(骑士周游问题)初探》
for (int j= 0; j< N; ++j)
《跳马问题(骑士周游问题)初探》 printf(
%2d, chess[i][j]);
《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》 }

《跳马问题(骑士周游问题)初探》 printf(
);
《跳马问题(骑士周游问题)初探》
return true;
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

int
main()
《跳马问题(骑士周游问题)初探》《跳马问题(骑士周游问题)初探》


{
《跳马问题(骑士周游问题)初探》
int x = 0;
《跳马问题(骑士周游问题)初探》
int y = 0;
《跳马问题(骑士周游问题)初探》 chess[x][y]
= 1;
《跳马问题(骑士周游问题)初探》 travel(x, y);
《跳马问题(骑士周游问题)初探》}


《跳马问题(骑士周游问题)初探》
《跳马问题(骑士周游问题)初探》

但很遗憾,实验证明贪心法并不是正确的,因为不能证明贪心选择一定会得到问题的解。可以举出反例:当马开始在(5, 3)位置时,使用贪心算法得不到可行路径,但使用改进后的回溯算法KnightTravel2,则可以解出结果。

综上所述,骑士周游问题不能使用贪心法求解。改进后的回溯法是一个可行的方案,但时间复杂度仍然很高。在王晓东的《计算机算法设计与分析》一书上看到该问题可以用分治递归法求解,但一直没有想出答案,网上也很难找到相关方面的资料。

【参考文献】

[1] 《计算机算法设计与分析(第2版)》 王晓东 电子工业出版社http://blog.csdn.net/eshow/article/details/1779307

    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/a754125462/article/details/8899621
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞