跳马问题也称为骑士周游问题,是算法设计中的经典问题。其一般的问题描述是:
考虑国际象棋棋盘上某个位置的一只马,它是否可能只走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)
* 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)