算法:马踏棋盘算法

在图中寻找哈密尔顿路径。

定义:将马随机放在国际象棋的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;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值