例题:求马的不同走法总数 问题描述:在一个4*5的棋盘上,马的起始位置坐标(纵,横)位置由键盘输入,求马能返回初始位置的所有不同走法的总数(马走过的位置不能重复,马走“日”字)。
算法分析: 由于棋盘的大小只有4*5,所以只需使用回溯算法,搜索马能返回初始位置的所有不同走法,效率基本上能达到要求。 递归的回溯算法可描述为: procedure search(now:position); {now是当前位置} begin for 马从当前位置now出发走一步到位置next的每一种走法 do begin if next在棋盘内 and next位置没有走过 then if next=出发点 then 不同走法总数加1 else begin 标记next已经走过了; search(next); 取消位置next的标记; end; end; end; 下面讨论算法的具体实现。 棋盘用坐标表示,点P(x,y)表示棋盘上任一个点,x,y的范围是:1<=x<=4,1<=y<=5。
从P(x,y)出发,下一步最多有8个位置,记为P1,P2,„„,P8,若用k表示这8个方向,则k=1,2,„,8。即马从P点出发,首先沿k=1的方向行进,当在此方向走完所有的不同走法后,就进行回溯,改变k=2方向继续行进„„
各点坐标的计算。设P点坐标为(x,y),则能到达点的坐标分别为P1(x+1,y-2),P2(x+2,y-1),„,P7(x-2,y-1),P8(x-1,y-2)。为简化坐标的计算,引入增量数组:
direction:array[1..8] of position=
((x:1;y:-2),(x:2;y:-1),(x:2;y:1),(x:1;y:2),
(x:-1;y:2),(x:-2;y:1),(x:-2;y:-1),(x:-1;y:-2));
则按方向k能到达点的坐标是: Pk(x+direction[k].x,y+direction[k].y)。 程序如下:
#include <cstdlib>
#include <iostream>
using namespace std;
#define row 4
#define line 5
struct position
{
int x,y;
};
const position direction[8]=
{(1,-2),(2,-1),(2,1),(1,2),(-1,2),(-2,1),(-2,-1),(-1,-2)};
int pass[4][5];
position start;
int total;
void search(position now)
{
int i;
position next;
for (i=0;i<8;i++)
{
next.x=now.x+direction[i].x;
next.y=now.y+direction[i].y;
if ((next.x>=0)&&(next.x<=row-1)&&(next.y>=0)&&(next.y<=line-1)&&(pass[next.x][next.y])==0)
if((next.x==start.x)&&(next.y==start.y))
total++;
else
{
pass[next.x][next.y]=1;
search(next);
pass[next.x][next.y]=0;
}
}
}
int main(int argc, char *argv[])
{
total=0;
for(int i=0;i<row;i++)
for(int j=0;j<line;j++)
{
pass[i][j]=0;
}
cout<<"输入开始位置"<<endl;
cin>>start.x>>start.y;
search(start);
cout<<"TOTAL="<<total<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}