zoukankan      html  css  js  c++  java
  • 数据结构(二)栈与队列---回溯法之八皇后问题

    (0)预备知识

    C语言复习---二维数组和二级指针的关系:没关系,别瞎想(重点)

    (一)问题描述

    要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉。规则是皇后能吃掉同一行、同一列、同一对角线的棋子。如下图即是两种方案:

    (二)递归代码实现

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    
    #define ERROR 0
    #define OK 1
    
    typedef int Status;
    
    int count = 0;
    
    /*
    int *chess[8]    代表棋盘,chess代表每一行指针
    int row是当前行
    int col是当前列
    上面确定了一个位置
    */
    Status noDanger(int(*chess)[8], int row, int col)
    {
        int i = 0;
        int r, c;
    
        //先判断当前列
        for (i = 0; i < 8; i++)
            if (chess[i][col] != 0)
                return ERROR;
    
        //再将当前行设置为-1
        for (i = 0; i < 8; i++)
            if (chess[row][i] != 0)
                return ERROR;
    
        //再将斜行列设置为-1,分为4个方向,
        //左上:行列减一,
        r = row;
        c = col;
        while (r >= 0 && c >= 0)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r--;
            c--;
        }
        //右上:行减一列加一,
        r = row;
        c = col;
        while (r >= 0 && c < 8)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r--;
            c++;
        }
        //左下:行加一列减一,
        r = row;
        c = col;
        while (r < 8 && c >= 0)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r++;
            c--;
        }
        //右下:行加一列加一,
        r = row;
        c = col;
        while (r < 8 && c < 8)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r++;
            c++;
        }
        return OK;
    }
    
    
    /*
    int *chess[8]    代表棋盘,chess代表每一行指针
    int row是当前行
    int col是当前总列数
    */
    void EightQueen(int(*chess)[8], int row, int cols)
    {
        int chess2[8][8];
        int i, j;
        for (i = 0; i < 8;i++)
            for (j = 0; j < 8;j++)
                chess2[i][j] = chess[i][j];
    
        //row==8是递归结束条件
        if (row==8)    //从0-7就判断完毕,到第九行是不存在的,说明已经找到所有的位置,可以打印了
        {
            printf("the number of %d ways
    ", count + 1);
            for (i = 0; i < 8;i++)
            {
                for (j = 0; j < 8; j++)
                    printf("%d ", *(*(chess2 + i) + j));
                printf("
    ");
            }
            printf("
    ");
            count++;    //获取的正确方案加一
        }
        else
        {
            //判断当前行的每一列是否有效
            for (j=0;j<cols;j++)
            {
                if (noDanger(chess, row, j))    //若是这个位置不危险,可以存放皇后
                {
                    for (i = 0; i < 8;i++)
                    {
                        *(*(chess2 + row) + i) = 0;    //将这一行设为0
                    }
                    *(*(chess2 + row) + j) = 9;    //当前存放皇后的位置设置为9
    
                    //进行递归,继续向下
                    EightQueen(chess2, row + 1, cols);
                }
            }
        }
    }
    
    int main()
    {
        int chess[8][8] = { 0 };
    
        EightQueen(chess, 0, 8);
        printf("end
    ");
    
        system("pause");
        return 0;
    }

    递归函数EightQueen

    void EightQueen(int(*chess)[8], int row, int cols)
    {
        int chess2[8][8];  //由于可以走到的方案太多,我们最好使用一个临时变量去存储原来棋盘位置,不然每次保存现场也是释放消耗时间空间的
        int i, j;
        for (i = 0; i < 8;i++)
            for (j = 0; j < 8;j++)
                chess2[i][j] = chess[i][j];
    
        //row==8是递归结束条件
        if (row==8)    //从0-7就判断完毕,到第九行是不存在的,说明已经找到所有的位置,可以打印了
        {
            printf("the number of %d ways
    ", count + 1);
            for (i = 0; i < 8;i++)
            {
                for (j = 0; j < 8; j++)
                    printf("%d ", *(*(chess2 + i) + j));
                printf("
    ");
            }
            printf("
    ");
            count++;    //获取的正确方案加一
        }
        else
        {
            //判断当前行的每一列是否有效
            for (j=0;j<cols;j++)  //我们在参数中,获取了应该操作的行数,现在我们应该对列进行循环,判断该行中列的正确与否
            {
                if (noDanger(chess, row, j))    //若是这个位置不危险,可以存放皇后 //虽然我们大多使用的是临时棋盘chess2,但在这里我们需要使用到参数传递过来的上级棋盘,因为我们在判断合法位置后,会修改临时棋盘,导致临时棋盘该位置被填充,变为不合法。不会再进入循环
                {
                    for (i = 0; i < 8;i++)
                    {
                        *(*(chess2 + row) + i) = 0;    //将这一行设为0  //我们在这里修改了临时棋盘,所以我们在上面判断位置合法性,不要使用临时棋盘,而是使用上级棋盘chess
                    }
                    *(*(chess2 + row) + j) = 9;    //当前存放皇后的位置设置为9
    
                    //进行递归,继续向下
                    EightQueen(chess2, row + 1, cols);  //继续递归,传入临时棋盘
                }
            }
        }
    }

    位置合法性noDanger

    我们需要对该位置的行,列,斜行列进行判断,其中斜线上我们需要判断左上,右上,左下,右下四个方向
    Status noDanger(int(*chess)[8], int row, int col)
    {
        int i = 0;
        int r, c;
    
        //先判断当前列
        for (i = 0; i < 8; i++)
            if (chess[i][col] != 0)
                return ERROR;
    
        //再将当前行设置为-1
        for (i = 0; i < 8; i++)
            if (chess[row][i] != 0)
                return ERROR;
    
        //再将斜行列设置为-1,分为4个方向,
        //左上:行列减一,
        r = row;
        c = col;
        while (r >= 0 && c >= 0)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r--;
            c--;
        }
        //右上:行减一列加一,
        r = row;
        c = col;
        while (r >= 0 && c < 8)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r--;
            c++;
        }
        //左下:行加一列减一,
        r = row;
        c = col;
        while (r < 8 && c >= 0)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r++;
            c--;
        }
        //右下:行加一列加一,
        r = row;
        c = col;
        while (r < 8 && c < 8)
        {
            if (chess[r][c] != 0)
                return ERROR;
            r++;
            c++;
        }
        return OK;
    }

  • 相关阅读:
    7,MongoDB 之 Limit 选取 Skip 跳过 Sort 排序
    Python的while else
    linux route
    NCO
    rand和randn
    vi常用操作
    Linux常用命令
    Jmeter的NON-GUI模式
    Linux下安装jdk&Jmeter
    MySql安装完成后,Navicat连接不上的问题
  • 原文地址:https://www.cnblogs.com/ssyfj/p/9446947.html
Copyright © 2011-2022 走看看