现在的位置: 首页 > 综合 > 正文

数据结构经典算法(7)骑士走棋盘

2018年04月21日 ⁄ 综合 ⁄ 共 2295字 ⁄ 字号 评论关闭

说明:骑士旅游(Knighttour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出

已不可考,骑士的走法为西洋棋的走法,骑士可以由任一个位置出发,它要如何走完[所有的位 置?

解法:骑士的走法,基本上可以使用递回来解决,但是纯綷的递回在维度大时相当没有效率,

 一个聪明的解法由J .C. Warnsdorff在1823年提出,简单的说,先将最难的位置走完,接下来的路 就宽广了,骑士所要走的下一步,「为下一步再选择时,所能走的步数最少的一步。 」 个,使用这 方法,在不使用递回的情况下,可以有较高的机率找出走法(找不到走法的机会也是有的) 。

 

#include <iostream>
#include <iomanip>
#define SIZE 8
using namespace std;
bool travel(int board[][SIZE],int x,int y);        
int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y);
int min(int board[][SIZE],int *nexti,int *nextj,int count);  
void printBoard(int borad[][SIZE]);
int main()
{
    int start_x;
    int start_y;
    cout<<"输入初始位置"<<endl;
    cin>>start_x>>start_y;
    int board[SIZE][SIZE]={0};
    if(travel(board,start_x,start_y))cout<<"遍历成功!"<<endl;
    else cout<<"遍历失败!"<<endl;
    printBoard(board);
}
bool travel(int board[][SIZE],int x,int y)
{
    board[x][y]=1;                   //当前位置为第1次走的位置
    int nexti[SIZE]={0};
    int nextj[SIZE]={0};             //下一跳初始化
    int i=x;
    int j=y;
    int MAX=SIZE*SIZE;
    int count=0;
    for(int m=2;m<=MAX;m++)          //遍历棋盘
    {
        count=possible(board,nexti,nextj,i,j);//得到可能的下一跳数目
        if(count==0)return false;    //无可走方向,遍历失败
        int min_Direction=min(board,nexti,nextj,count);//在多个可能方向中查找下一跳方向最少的方向
        i=nexti[min_Direction];      //下一跳位置坐标
        j=nextj[min_Direction];
        board[i][j]=m;               //当前位置为第m次走的位置
    }
    return true;
}
int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y)
{
    int mvi[SIZE]={-2,-1,1,2,2,1,-1,-2};    //下一跳可能的八个方向(x坐标y坐标)
    int mvj[SIZE]={1,2,2,1,-1,-2,-2,-1};
    int count=0;
    for(int i=0;i<SIZE;++i)
    {
        int tmpx=x+mvi[i];
        int tmpy=y+mvj[i];
        if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue; //越界,不是可行方向
        if(board[tmpx][tmpy]==0)                  //未走过,找到一个可能方向
        {
            nexti[count]=tmpx;
            nextj[count]=tmpy;
            count++;
        }
    }
    return count;                              //返回可能的方向数
}
int min(int board[][SIZE],int *nexti,int *nextj,int count)
{
    int mvx[SIZE]={-2,-1,1,2,2,1,-1,-2};
    int mvy[SIZE]={1,2,2,1,-1,-2,-2,-1};
    int exist[SIZE]={0};                   //记录该方向的下一跳方向的数目
    int min_direction=-1;                  //初始化最小方向数的方向
    if(count==1)min_direction=0;           //只有一个可行方向
    else
    {
        for(int i=0;i<count;++i)           //在所有可行方向中遍历
        {
            for(int j=0;j<SIZE;++j)        //计算每一个方向下一跳的数目
            {
                int tmpx=nexti[i]+mvx[j];
                int tmpy=nextj[i]+mvy[j];
                if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue;
                if(board[tmpx][tmpy]==0)
                {
                    exist[i]++;
                }
            }
        }
        int min=exist[0];                 //取其中最小数目的方向
        min_direction=0;
        for(int i=1;i<count;++i)          //此处count开始错为SIZE,一直未查出错误
                                          //exist数组只有count位不为0
        {
            if(exist[i]<min)
            {
                min=exist[i];
                min_direction=i;
            }
        }
    }
    return min_direction;
}
void printBoard(int board[][SIZE])
{
     for(int i=0;i<SIZE;++i)
     {
         for(int j=0;j<SIZE;++j)
         {
             cout<<setw(2)<<board[i][j]<<"  ";
         }
         cout<<endl;
     }
}

抱歉!评论已关闭.