代码改变世界

回溯法解马的遍历问题

2012-06-08 15:36  youxin  阅读(3396)  评论(0编辑  收藏  举报

  马的遍历问题:在n*m的棋盘上,马只能走日字。马从位置(x,y)处出发,把棋盘的每一点都走一次,且只走一次,找出所有路径。

问题分析:行n,列m,马在不出边界的情况下有8个方向可以行走(走日字),如当前坐标为(x,y),则行走后的坐标可以为:

(x+1,y+2) (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)

 

回溯法算法设计: 搜索空间是n*M个点,约束条件是不出边界且每个点只经过一次,节点的扩展规则如上所述。

   搜索过程是从任一点(x,y)出发,按深度优先原则,从8个方向尝试一个可以走的点,直到走过n*m个点。用递归容易实现。

注意:问题要求找出所有可能的解。就要注意回溯过程的清理现场工作,就是置当前位置为未经过。

数据结构设计:用一个变量dep记录递归深度,也就是走过的点数。当dep=n*m;找到一组解。

用n*m的二维数组记录马走过的过程,初始值为0表示未经过,起点存储的是1,终点存储的是n*m。

#include<iostream>
using namespace std;
void output();
int n=5,m=4;
int fx[8]={1,2,2,1,-1,-2,-2,-1};
int fy[8]={2,1,-1,-2,-2,-1,1,2};
int a[5][4]; //下标从1开始
int dep,x,y,count;
 
bool check(int x,int y)
{
     if(x>=1&&x<=n&&y>=1&&y<=m&&(!a[x][y]))
         return true;
     else
         return false;

}
    
void find(int x,int y,int dep)
{
    int i,xx,yy;
    for(i=1;i<=8;i++) //加上方向增量,形成新的坐标
    {
        xx=x+fx[i];
        yy=y+fy[i];
        if(check(xx,yy)) //判断新坐标是否出界,是否已走过
        {
            a[xx][yy]=dep; 
            if(dep==n*m)
                output();
            else
                find(xx,yy,dep+1);

            
           a[xx][yy]=0; //回溯,恢复未走未走
            
        }
         
    }
}

void output()
{
    count++;
    cout<<"\n";
    cout<<"count="<<count;
    for(y=1;y<=n;y++)
    {
        cout<<endl;
        for(x=1;x<=m;x++)
            cout<<a[y][x]<<ends;
    }
}

int main()
{
    int i,j;
    count=0;
    dep=1;
    cout<<"please input x,y";
    cin>>x>>y;
    if(x>n||y>m||x<1||y<1)
    {
        cout<<"input error";
        return -1;
    }
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            a[i][j]=0;
    a[x][y]=1;
    find(x,y,2);
    if(count==0)
        cout<<"no solution!";
    else
        cout<<"nambers of solution="<<count<<endl;
}
 

代码输出好像有错误。

http://zhidao.baidu.com/question/44427050.html