数据结构与算法|马踏棋盘算法(小甲鱼)C语言代码的算法分析

马踏棋盘算法(骑士周游问题)的算法分析

C语言代码部分来自小甲鱼的《数据结构与算法》

文章目录

    • 马踏棋盘算法(骑士周游问题)的算法分析
  • 一、C语言代码实现
  • 二、代码分析与算法思路

题目要求

​ 国际象棋的棋盘为8*8的方格棋盘,现将“马”放在任意指定的方格中,按照“马”走棋的规则将“马”进行移动。要求每个方格只能进入一次,最终使得“马”走遍棋盘64个方格。

马踏棋盘的一个解:

对于在n*n的棋盘上,当n>=5且为偶数的时候,以任意点作点都有解。


回溯法:一条路走到黑,碰壁了再回来一条路走到黑…一般和递归可以很好的搭配使用,还有深度优先搜索(DFS)。

哈密尔顿路径:图G中的哈密尔顿路径指的是经过图G中每个顶点,且只经过一次的一条轨迹。如果这条轨迹是一条闭合的路径(从起点出发不重复地遍历所有点后仍能回到起始点),那么这条路径称为哈密尔顿回路。

一、C语言代码实现

#include
#include

#define X 8
#define Y 8

int chess[X][Y];
//找到基于(x,y)位置的下一个可走的位置
int nextxy(int *x,int *y,int count)
{
     
    switch(count)
    {
     
        case 0:
            if(*x+2<=X-1&& *y-1>=0&&chess[*x+2][*y-1]==0)
            {
     
                *x+=2;
                *y-=1;
                return 1;
            }
            break;
        case 1:
            if(*x+2<=X-1&& *y+1<=Y-1&&chess[*x+2][*y+1]==0)
            {
     
                *x+=2;
                *y+=1;
                return 1;
            }
            break;
        case 2:
            if(*x+1<=X-1&& *y-2>=0&&chess[*x+1][*y-2]==0)
            {
     
                *x+=1;
                *y-=2;
                return 1;
            }
            break;
        case 3:
            if(*x+1<=X-1&& *y+2<=Y-1&&chess[*x+1][*y+2]==0)
            {
     
                *x+=1;
                *y+=2;
                return 1;
            }
            break;
        case 4:
            if(*x-1>=0&& *y-2>=0&&chess[*x-1][*y-2]==0)
            {
     
                *x-=1;
                *y-=2;
                return 1;
            }
            break;
        case 5:
            if(*x-1>=0&& *y+2<=Y-1&&chess[*x-1][*y+2]==0)
            {
     
                *x-=1;
                *y+=2;
                return 1;
            }
            break;
        case 6:
            if(*x-2>=0&& *y-1>=0&&chess[*x-2][*y-1]==0)
            {
     
                *x-=2;
                *y-=1;
                return 1;
            }
            break;
        case 7:
            if(*x-2>=0&& *y+1<=Y-1&&chess[*x-2][*y+1]==0)
            {
     
                *x-=2;
                *y+=1;
                return 1;
            }
            break;
        default:
            break;
    }
    return 0;
}

void print()
{
     
    int i,j;

    for(i=0;i<X;i++)
    {
     
        for(j=0;j<Y;j++)
        {
     
            printf("%2d\t",chess[i][j]);
        }
        printf("\n");
    }

    printf("\n");
}



//深度优先遍历棋盘
//(x,y)为位置坐标
//tag是标记变量,每走一步,tag+1
int TravelChessBoard(int x,int y,int tag)
{
     
    int x1=x, y1=y, flag=0 , count=0;
    chess[x][y] =tag;

    if( X*Y == tag )
    {
     
        //打印棋盘
        print();
        return 1;
    }

    //找到马的下一个可走的坐标(x1,y1),如果找到flag=1,否则为0
    flag = nextxy(&x1,&y1,count);
    while( 0 == flag && count < 7)
    {
     
        count++;
        flag = nextxy(&x1,&y1,count);
    }

    while ( flag )
    {
     
        if( TravelChessBoard(x1,y1,tag+1) )
        {
     
            return 1;
        }

        //继续找到马的下一步可走的坐标(x1,y1),如果找到flag=1,否则为0
        x1=x;
        y1=y;
        count++;

        flag = nextxy(&x1,&y1,count);
        while( 0 == flag && count < 7)
        {
     
            count++;
            flag = nextxy(&x1,&y1,count);
        }
    }

    if( 0 == flag)
    {
     
        chess[x][y] = 0;
    }

    return 0;
}

int main()
{
     
    int i, j;
    clock_t start,finish;

    start=clock();

    for( i=0; i < X; i++ )
    {
     
        for( j=0; j < Y; j++)
        {
     
            chess[i][j] = 0;
        }
    }

    if(!TravelChessBoard(0,0,1))
    {
     
        printf("抱歉,马踏棋盘失败!\n");
    }

    finish=clock();
    printf("本次计算一共耗时:%f秒\n\n",(double)(finish-start)/CLOCKS_PER_SEC);

    return 0;
}

二、代码分析与算法思路

这里的起始位置是(0,0):如果起始位置是(2,0),可能需要很久的运行时间——因为由于一共有64次递归,每次递归最坏的情况可以有8次迭代,根据起始位置的不同,假设是最极端的情况时,可能需要8^(64)的时间复杂度。

算法思路

  1. 初始化二维数组

  2. 进入马踏棋盘算法TracelChessBoard(int x, int y,int tag)

    1. 初始化:x1=x,y1=y,flag=0,count=0

    2. 先假设该层马踏算法的位置行得通:chess[x][y]=tag

    3. 判断tag==X*Y:

      • 如果是:返回1。(已跑到最底层马踏算法:当tag==64时,算法成功,并完成了)
    4. 依次寻找马踏的下一个位置(count++)(第一次马踏):

      • 如果找到:改变x1和y1到马踏的下一个位置上,并返回1到flag;
      • 如果一直没找到(该位置无法进行下一步马踏):返回0到flag;
    5. 如果flag==1:

      • 如果下层马踏棋盘算法(基于第一次马踏后的位置TracelChessBoard(x1,y1,tag+1)返回1,则此层马踏算法结束:返回1!(如果马踏的下一步也成功,返回1)

        1. 如果下层马踏棋盘算法TracelChessBoard(x1,y1,tag+1)一直返回1,(直到tag=X*Y时)则算法结束。
        2. 如果某一层马踏棋盘算法跳返回0,则(此时马踏的该位置的tag=0,flag=0)
      • (能进行到该步,意味着flag=0,该层位置行不通)初始化:x1=x,y1=y,该层count+=1(该位置(第一次马踏后的位置)都是死路,取消第一次马踏的位置,继续寻找该层马踏算法的下一个第一次马踏:count++);

      • 依次寻找马踏的下一个位置(count++):

        1. 如果找到:改变x1和y1到马踏的下一个位置上,并返回1到flag;

        2. 如果一直没找到(含有该层马踏算法的起始位置的路线都是死路):返回0到flag;

    6. 如果flag==0(即该层马踏算法都是死路):该层马踏算法的位置行不通,初始化该位置:chess[x][y]=0

    7. 返回0;

  3. 判断经过层层递归后的马踏棋盘算法:

    1. 如果算法最终返回0:算法失败!
    2. 如果算法最终返回1:打印二维数组,算法成功!

简述((Position>>>)position1>>>position2):

  1. 马儿来到这个岔路口positon1(如果有上一个岔路口,则假设为Position):

    1. 如果这个岔路口是终点,则胜利了。

    2. 马儿选择一条未走过、能走的路(从左往右选):

      1. 有得选,去到下个岔路口position2:

        1. 下个岔路口position2有路能走:记录岔路口position1,沿着该路到下个岔路口position2(令Position=position1,position1=position2),跳到(1);
        2. 下个岔路口(position2)无路能走:返回上一个岔路口(position1);

        以上两步可以不要,可以走到下个岔路口position2时,直接跳至(1)。

      2. 没得选,返回上一个岔路口(令position1=Position),跳至(1)。

你可能感兴趣的:(Python,|数据结构与算法,算法,c语言)