在图中寻找哈密尔顿路径。
定义:将马随机放在国际象棋的8×8棋盘Board[0~7][0~7]的某个方格中,马按走棋规则进行移动。要求每个方格只进入一次,走遍棋盘上全部64个方格。
算法:如图:
马踏棋盘的一个点:对于n*n的棋盘上,当n》=5且为偶数的情况下,以任意点都有解。
一些相关的知识:
1、回溯法
思想很简单,一条路走到黑,碰壁了再回来一条路走到黑,一般和递归可以很好的搭配使用。比如深度优先搜索。
2、哈密尔顿路径
图G中的哈密尔顿路径指的是经过G中的每个顶点,且只经过一次的一条路径。
编程的思路:
用一个二位数组chess[X][Y]当做棋盘,先要实现马在棋盘(x, y)时,能走到的地方,就像上图中的0~7个位置。
接下来就是遍历棋盘方法:假设马儿的坐标为(x,y),那么可供选择的下一个位置共有8种可能。我们所要做的,就是从0号位置开始,依次判断新的马儿位置是否可用,不可用的话(即马儿已经走过该位置),则遍历下一个可能的1号位置,直到7号位置停止,如果没有可用位置,则进行回溯,如果回溯到了起始位置,则表示此路不通,即无法从该位置开始遍历整个棋盘。如果在遍历0-7号位置的过程中,发现有可用位置,则将该位置坐标赋予(x,y)。之后,利用递归,再次寻找马儿的新的跳跃位置。直到马儿跳了64次时停止,此时,马儿就已经将整个棋盘走过了。
#include <stdio.h>
#include <time.h>
#include <iostream>
using namespace std;
#define X 8
#define Y 8
int chess[X][Y]; //棋盘
//找到基于(x,y)位置下一个可以走的位置
int nextxy(int *x, int *y, int count)
{
switch(count)
{
case 0:
if ( *x+2 <= X-1 && *y-1 >= 0 && chess[*x+2][*y-1] == 0 )
{
*x += 2;
*y -= 1;
return 1;
}
break;
case 1:
if ( *x+2 <= X-1 && *y+1 <= Y-1 && chess[*x+2][*y+1] == 0 )
{
*x += 2;
*y +=1;
return 1;
}
break;
case 2:
if ( *x+1 <= X-1 && *y-2 >=0 && chess[*x+1][*y-2] == 0)
{
*x=*x+1;
*y=*y-2;
return 1;
}
break;
case 3:
if ( *x+1 <= X-1 && *y+2 <= Y-1 && chess[*x+1][*y+2] == 0 )
{
*x=*x+1;
*y=*y+2;
return 1;
}
break;
case 4:
if ( *x-2 >= 0 && *y-1 >= 0 && chess[*x-2][*y-1] == 0)
{
*x = *x-2;
*y = *y-1;
return 1;
}
break;
case 5:
if ( *x-2 >= 0 && *y+1 <= Y-1 && chess[*x-2][*y+1] == 0)
{
*x = *x-2;
*y = *y+1;
return 1;
}
break;
case 6:
if ( *x-1 >= 0 && *y-2 >=0 && chess[*x-1][*y-2] == 0)
{
*x = *x-1;
*y = *y-2;
return 1;
}
break;
case 7:
if ( *x-1 >= 0 && *y+2 <= Y-1 && chess[*x-1][*y+2] == 0)
{
*x = *x-1;
*y = *y+2;
return 1;
}
break;
default:
break;
}
return 0;
}
//深度优先遍历棋盘
//(x,y)为位置坐标
//tag是标记变量,每走一步,tag+1
int TraveChessBoard(int x, int y, int tag)
{
int x1 = x, y1 = y, flag = 0, count = 0;
chess[x][y] = tag;
//当tag = 64时,成功遍历一遍了
if ( X*Y == tag )
{
print();
return 1;
}
flag = nextxy(&x1, &y1, count); //找到马的下一个可走的坐标(x1,y1),如果找到flag=1,否则为0
//如果count进入后,就失败了则继续尝试下一个位置
while( 0 == flag && count < 7 )
{
count++;
flag = nextxy(&x1, &y1, count);
}
//当查找到了下一个位置
while ( flag )
{
//就递归调用自己,继续走下一次,如果没有就回溯
if (TraveChessBoard(x1, y1, tag+1))
{
return 1;
}
//当上面没有查找到位置,则进行回溯,进行下一次查找
x1 = x;
y1 = y;
count++;
flag = nextxy(&x1, &y1, count);//继续找到马的下一步可走的坐标(x1,y1),如果找到flag=1,否则为0
while( 0 == flag && count < 7 )
{
count++;
flag = nextxy(&x1, &y1, count);
}
}
if ( 0 == flag )
{
chess[x][y] = 0;
}
return 0;
}
void print()
{
int i, j;
for ( i=0, i < X, i++)
{
for ( j=0, j < Y, j++)
{
printf("%2d\t",chess[i][j]);
}
cout <<endl;
}
cout<<endl;
}
int main()
{
int i,j;
clock_t start,finish;
start = clock();
for ( i=0, i < X; i++)
{
for ( j=0, j < Y, j++)
{
chess[i][j] = 0;
}
}
if ( !TraveChessBoard(2,0,1))
{
cout << "抱歉,马踏棋盘失败" << endl;
}
finish = clock();
cout << (double)(finish-start)/CLOCKS_PER_SEC;
return 0;
}