c语言数据结构之马踏棋盘

c语言数据结构之马踏棋盘

马踏棋盘游戏
(一)思路:
马随机放在国际象棋的 8×8 棋盘 Board[07][07]的某个方格中,马按走棋规则进行移动。要求每个方格只进入一次,走遍棋盘上全部 64 个方格。,求出马的行走路线,并按求出的行走路线,将数字 1,2,…,64 依次填入一个 8×8 的方阵,输出之。

(二)步骤分析
1、马踏棋盘问题(骑士周游问题)实际上是图的深度优先搜索(DFS)的应用。
2、解决步骤与思路:
(1)创建棋盘(chessBoard),是一个二维数组,创建栈用于存储访问顺序和用于回朔;
(2)将当前位置设置为已经访问,然后根据当前位置,计算马能走哪些位置,并放入到一个,最多有8个位置,每走一步,就使用top+1;
(3)通过贪心算法进行优化:根据当前这一步的所有的下一步的选择位置,进行非递减排序(例如:1,2,2,2,3,3,4就属于非递减排序);
(4)遍历栈中存放的所有位置,看看哪个可以走通,如果走通,就继续,走不通,就回溯;
(5)判断马是否完成了任务,使用top和应该走的步数比较,如果没有达到数量,则表示没有完成任务,将整个棋盘置为0。

/**
 * @file 马踏棋盘.c
 * @author IT小阳
 * @brief 
 * @version 0.1
 * @date 2022-06-27
 * 
 * @copyright Copyright (c) 2022
 * 
 * 每次选择位置都是最优解
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define Row 8
#define Col 8
#define maxStep 64

typedef struct
{
    int abscissa;  //横坐标
    int ordinate;  //纵坐标
    int direction; //方向
} SqStack;

//储存路径(并置零)
int ChessBoard[Row + 1][Col + 1] = {}; 

//分别有(1 ~ 8)个方向
int HTry1[8] = {1, -1, -2, 2, 2, 1, -1, -2};
int HTry2[8] = {2, -2, 1, 1, -1, -2, 2, -1};

SqStack PointStack[maxStep];
int top = -1; //栈顶

int num = 0;         //记录结果数

//棋盘打印方法
void printChessBoard()
{
    printf("棋盘路径是:\n");
    for (int i = 1; i <= Row; i++)
    {
        for (int j = 1; j <= Col; j++)
        {
            printf("%5d ", ChessBoard[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
}

//入栈
void push(int abscissa, int ordinate)
{
    ++top;
    PointStack[top].abscissa = abscissa;
    PointStack[top].ordinate = ordinate;
    PointStack[top].direction = -1; //初始化方向
}

//出栈
void pop()
{
    PointStack[top].abscissa = 0;
    PointStack[top].ordinate = 0;
    PointStack[top].direction = -1; //初始化方向
    --top;
}

//标记棋盘
//棋子的行走路径
void markChessBoard(int abscissa, int ordinate)
{
    ChessBoard[ordinate][abscissa] = top + 1;
}

//初始化
//起点坐标
void InitStartPoint()
{
    int x, y;

    //输入起始坐标点
    printf("请输入起始点(x,y):");
    scanf("%d,%d", &x, &y);
    while (((x > Col || x <= 0) || (y > Row || y <= 0)))
    {
        if ((x > Col || x <= 0) || (y > Row || y <= 0))
        {
            printf("输入的坐标超出范围,请重新输入(0~8):");
            scanf("%d,%d", &x, &y);
        }
    }
    //入首栈
    push(x, y);
    //标记路径
    markChessBoard(x, y);
}

//主逻辑
void run()
{
    int xNow, yNow;//记录当前棋子位置

    
    while(1)
    {
        //栈满
        if (top == maxStep - 1)
        {
           break;
        }

        xNow = PointStack[top].abscissa;
        yNow = PointStack[top].ordinate;

        //检查该点可以走的所有节点得出最优解(少的先走)
        int count[8] = {};

        for (int i = 0; i < Row; i++)
        {
            int xNext = xNow, yNext = yNow;
            xNext += HTry1[i];
            yNext += HTry2[i];
            if (xNext > 0 && xNext < Row && yNext > 0 && yNext < Col && ChessBoard[xNext][yNext] == 0)
            {
                for (int j = 0; j < Col; j++)
                {
                    int xNext_Next = xNext, yNext_Next = yNext;
                    xNext_Next += HTry1[j];
                    yNext_Next += HTry2[j];
                    if (xNext_Next > 0 && xNext_Next < Row && yNext_Next > 0 && yNext_Next < Col && ChessBoard[xNext_Next][yNext_Next] == 0)
                    {
                        count[i]++;
                    }                   
                }   
            }         
        }

        //对方向进行排序,实际要走的方向记录在directionNext中
        int directionNext[8] = {};
        int temp = 9;
        int k = 0;
        for (int i = 0; i < 8; i++)
        {
            temp = 9;
            for (int j = 0; j < 8; j++)
            {
                if (count[j] < temp)
                {
                    directionNext[i] = j;
                    temp = count[j];
                    k = j;
                }
            }
            count[k] = 9;
        }

        //走下一步
        int direnow = 0;
        for (direnow = PointStack[top].direction + 1; direnow < 8; direnow++)
        {
            int xRealNext = xNow, yRealNext = yNow;
            xRealNext += HTry1[directionNext[direnow]];
            yRealNext += HTry2[directionNext[direnow]];
            PointStack[top].direction += 1;
            if (xRealNext <= Col && xRealNext > 0 && yRealNext <= Row && yRealNext > 0 && ChessBoard[yRealNext][xRealNext] == 0)
            {
                push(xRealNext, yRealNext);
                markChessBoard(xRealNext, yRealNext);
                break;
            }
        }

        //判断无路可走出栈
        if (PointStack[top].direction >= 7)
        {
            int x, y;
            x = PointStack[top].abscissa;
            y = PointStack[top].ordinate;
            ChessBoard[y][x] = 0; //棋盘标记取消
            pop();
        }
    }
}

int main()
{
    InitStartPoint();
    clock_t start, finish;
    start = clock();
    
    //主逻辑
    run();

    finish = clock();
    printChessBoard();
    printf("运行用时:%f 秒!\n", (double)(finish - start) / CLOCKS_PER_SEC);
}
  • 0
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值