. 编写程序求解骑士巡游问题:在n行n列的棋盘上(如n=5),假设一位骑士(按象棋中“马走日”的行走法)从

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了. 编写程序求解骑士巡游问题:在n行n列的棋盘上(如n=5),假设一位骑士(按象棋中“马走日”的行走法)从相关的知识,希望对你有一定的参考价值。

这个是我之前做的算法,但然我也是参考了网上提供的思想来做的。这个思想很广泛。把你输入的一个点为第一步,接着搜他可走8个方向中每一个可走的点,并记录这样可走的点的位置。再把这些记录的点再搜他可走的8个方向,但这些只要记录8个方向中可走方向的数目。接着就走方向最少的一条路。这样难走的路在前面已经走了,后面的路就好走很多了,一般都能找到方向。当然还有递归这种算法,但高维度的递归是没有意议的,电脑是算不出来的或着用很长时间才能算出来。下面是我的算法

#include<iostream>
using namespace std;
//定义棋盘的大小
#define N 8
#define LOSE 0
#define SUCCEED 1

void printknightgo(); //输出结果
int knightgo(int x,int y); //运算走法

int chessboard[8][8] = 0 ; //建立棋盘

void main()

int x,y;
cout<<"请输入坐标"<<endl;
cin>>x>>y; //输入坐标
if(knightgo(x,y)) //开始运算走法,如果成功则返回成功,否则返回失败
cout<<"成功完成"<<endl;


else
cout<<"失败"<<endl;


printknightgo(); //输出结果


//输出结果的算法
void printknightgo()
for(int i = 0;i < N; i++)
for(int j = 0;j < N;j++)
cout<<chessboard[i][j]<<"\t";

cout<<endl;



int knightgo(int x,int y)
chessboard[x][y] = 1;//将第一步标为1
int step;//走的步数
int nextx[8] = -1,1,-2,2,-2,2,-1,1;//走的X的步法
int nexty[8] = 2,2,1,1,-1,-1,-2,-2;//走的Y的步法
int recordNextx[8]=0;//记住下步可走X的位置,并用count来记数
int recordNexty[8]=0;//记住下步可走Y的位置,并用count来记数
int tempx,tempy;//用于临时记住X和Y
int i,j;//临时计数变量
int count = 0;//记住可循环的个数
int exist[8]=0;//第2次找8个方向每个可走的记录
for(int step = 2;step <=N*N;step++)//把输进来或循环的位置,找下一个能走的位置,并记住这些位置和可走的个数
for(i = 0;i < 8;i++) //把上次记录重置0;
recordNextx[i] = 0;
recordNexty[i] = 0;
exist[i] = 0;


count = 0;
for(i = 0;i < 8;i++)//第一次循环,找可走的个位置,并记录可走方向的个数
tempx = x + nextx[i];//tempx为临时记录X
tempy = y + nexty[i];//tempy为临时记录Y
if(chessboard[tempx][tempy] == 0 && tempx >= 0 && tempx < N && tempy >= 0 && tempy < N)//当这个位置没走过和不走出盘外时,才能记录
recordNextx[count] = tempx;
recordNexty[count] = tempy;//记录可走方向的x,y坐标
count++; //记录可以走的方向的个数



//把记住的位置,找他们的下个能走位置的个数,就是重复上面循环,只需记录可走方向的个数

if(count == 0)//如果没有出路则返回失败
return LOSE;


else //如果只有一条路,则走这一条路
if(count == 1)
x = recordNextx[0];//因为可走方向只有一个,所记录中就有recordNext(x,y)[0];
y = recordNexty[0];
chessboard[x][y] = step; //把第几步写入这个棋盘的位置


else//有多条路可以走的话
for(j = 0;j < count;j++)//第一个点记录的可走的方向,并找出们下一个方向可以走的的方向的个数
for(i = 0;i < 8;i++)//找第2个点8个方向可走的方向
tempx = recordNextx[j] + nextx[i];
tempy = recordNexty[j] + nexty[i];
if(chessboard[tempx][tempy] == 0 && tempx >= 0 && tempx < N && tempy >= 0 && tempy < N)//当这个位置没走过和不走出盘外时,才能记录
exist[j]++;//记录第2个点可走方向的个数



//找最方向个数最小的一条路
int min = exist[0];
int last = 0;//用于记住,recordNext(x,y)中可走方向中,能走方向数目最小的一个方向
for(i = 1;i < count;i++)//找出方向数目最小的数和方向
if(exist[i]<min)
min = exist[i];
last = i;



x = recordNextx[last];//将这个方向给x,y;
y = recordNexty[last];
chessboard[x][y] = step; //将这个步数写出这个棋盘





return SUCCEED;
参考技术A 给你个思路吧,把棋盘格子看成矩阵,可以用二维数组形式储存,让起始点(骑士)找到横坐标+-2,纵坐标+-1或者纵坐标+-2,横坐标+-1的位置,可设置函数,在函数中设置循环,先找是否有横坐标+2点,存在的话再找纵坐标+1点,返回1成功,失败则返回0,应该可以用递归函数来写

骑士巡游问题

问题:

  在 n × n 方格的国际象棋棋盘上,马(也称为骑士Knight)从任意指定的方格出发,以跳马规则(横一步竖两步或横两步竖一步),周游棋盘的每一个格子,要求每个格子只能跳过一次。

 

代码:

  思路什么的都在代码里,但是我写的代码太肤浅了, 5*5 的规模都要跑半天。

  所以真切的希望大家能够提出对我算法的批评与指教。

#include<iostream>
#include<fstream>
using namespace std;

//定义了8个方向,N表示右上的那个位置
#define N 0
#define NE 1
#define E 2
#define SE 3
#define S 4
#define SW 5
#define W 6
#define NW 7

struct step {//骑士巡游过的地方
    int x;
    int y;
};

void display(step steps[], int n)
{//展示骑士巡游的过程
    ofstream output("output.txt");
    int patch[10][10]={0};
    for (int i = 1; i <= n*n; i++)
    {
        patch[steps[i].x][steps[i].y]=i;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<patch[i][j]<<"    ";
            output<<patch[i][j]<<"    ";
        }
        cout<<endl;
        output<<endl;
    }
    cout<<endl;
    output<<endl;
}

bool isInside(int n, step place)
{//判断是否走出了地图
    if (place.x<1 || place.x>n || place.y<1 || place.y>n) return false;
    return true;
}

bool isOverlap(int map[][8], step place)
{//判断是否走重了
    if (map[place.x][place.y] == 1) return true;
    return false;
}

step overlook(step now, int dir)
{//往dir方向向前看一步,返回这样走之后的位置
    step then;
    switch (dir)
    {
    case N:then.x = now.x + 1, then.y = now.y - 2; break;
    case NE:then.x = now.x + 2, then.y = now.y - 1; break;
    case E:then.x = now.x + 2, then.y = now.y + 1; break;
    case SE:then.x = now.x + 1, then.y = now.y + 2; break;
    case S:then.x = now.x - 1, then.y = now.y + 2; break;
    case SW:then.x = now.x - 2, then.y = now.y + 1; break;
    case W:then.x = now.x - 2, then.y = now.y - 1; break;
    case NW:then.x = now.x - 1, then.y = now.y - 2; break;
    }
    return then;
}

void patrol(step steps[], int now, step then, int map[][8])
{//从now的位置向dir方向巡游下一步
    steps[now + 1] = then;
    //在map上标记已经走过
    map[steps[now + 1].x][steps[now + 1].y] = 1;
}

void KnightPatrol(int n, int count, step steps[], int map[][8])
{//n表示棋盘规模,count表示骑士已经走过的步数,steps记录骑士巡游过的点,map用来标记地图上每个点有没被走过

    if (count > n*n)
    {//如果骑士巡游过了所有的点
        display(steps, n);
    }

    for (int i = N; i <= NW; i++)
    {//对每个方向遍历

        step then = overlook(steps[count], i);//向i方向眺望一下
        if (isInside(n, then) && !isOverlap(map, then))
        {//如果骑士下一步没有跑到地图外面,且没有走到刚才走过的地方

            patrol(steps, count, then, map);
            for(int k=1;k<=count+1;k++)
            {
                cout<<steps[k].x<<","<<steps[k].y<<" ";
            }
            cout<<endl;
            KnightPatrol(n, count + 1, steps, map);
            map[steps[count+1].x][steps[count+1].y]=0;
        }
    }
}

int main()
{
    int n;
    cin >> n;
    step *steps = new step[n*n + 1];
    steps[1].x = 3;
    steps[1].y = 1;
    int map[8][8] = { 0 };
    map[3][1] = 1;
    KnightPatrol(n, 1, steps, map);
    system("pause");
}

 

以上是关于. 编写程序求解骑士巡游问题:在n行n列的棋盘上(如n=5),假设一位骑士(按象棋中“马走日”的行走法)从的主要内容,如果未能解决你的问题,请参考以下文章

069.骑士巡游

骑士巡游问题

骑士巡游的问题简述如下:在国际象棋盘上某一位置放置一个马的棋子,然后采用象棋中“马走日字”规则

数据结构与算法之深入解析“骑士在棋盘上的概率”的求解思路与算法示例

vijos p1729 Knights

P3355 骑士共存问题 网络流