ACM--回溯算法

来源:互联网 发布:深港通数据 编辑:程序博客网 时间:2024/04/29 01:12

例题:求马的不同走法总数 问题描述:在一个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;
}