回溯算法(Backtracking Algorithm)之八皇后问题

1. 回溯算法思想

前面讲过贪心算法并不能保证得到最优解,那怎么得到最优解呢?

  • 回溯思想,有点类似枚举搜索。枚举所有的解,找到满足期望的解。
  • 为了有规律地枚举所有可能的解,避免遗漏和重复,把问题求解的过程分为多个阶段。
  • 每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走。

2. 算法应用

2.1 八皇后问题

有一个8×8的棋盘,希望往里放8个棋子(皇后),每个棋子所在的行、列、对角线都不能有另一个棋子。请找到所有满足这种要求的放棋子方式。

在这里插入图片描述

  • 把这个问题划分成8个阶段,依次将8个棋子放到第一行、第二行、第三行。。。第八行
  • 放置的过程中,不停地检查当前的方法,是否满足要求
  • 如果满足,则跳到下一行继续放置棋子
  • 如果不满足,那就再换一种方法,继续尝试
  • 如果一整行都不能放下一颗,那么这种方法无效,退到上一行,上一行列位置+1,再往下尝试

在这里插入图片描述
从(0,0)位置开始放置
在这里插入图片描述
下标5的行,走到最后也没有放下这颗棋子,都不满足,那么退到下标4的行,列位置+1,从4列开始新的尝试
在这里插入图片描述
在这里插入图片描述
下标5的行容不下一颗棋子,再次回退,下标4行退到最后了,再往上退,下标3行棋子往右挪
在这里插入图片描述
在这里插入图片描述
下标7行放不下,退到6行
在这里插入图片描述
6行也容不下棋子,接着看5行
在这里插入图片描述
5行也不可以容下棋子,看第4行。。。(第一种可行解怎么还没出来,好累,就到这里吧,大家自行 ppt 画个图配合代码推一下就理解了)
在这里插入图片描述
第一个解是这样的,哈哈,挪了好长时间终于出来了
在这里插入图片描述

/**
 * @description: 回溯算法--八皇后问题
 * @author: michael ming
 * @date: 2019/7/7 0:10
 * @modified by: 
 */
#include <iostream>
using namespace std;
class EightQueen
{
    int result[8];//下标表示行,值表示queen在哪一列
    void printQueens(int *result)
    {
        int i,r,c,flag = 1;
        cout << "  ";
        for(i = 0; i < 8; ++i)
            cout << "▁";
        cout << endl;
        for(r = 0; r < 8; ++r)
        {
            cout << "┃";
            for(c = 0; c < 8; ++c)
            {
                if(result[r] == c)
                    cout << "★";
                else
                {
                    if(flag < 0)
                        cout << "  ";
                    else
                        cout << "■";
                }
                flag = -1*flag;
            }
            cout << "▏" << endl;
            flag = -1*flag;
        }
        cout << "  ";
        for(i = 0; i < 8; ++i)
            cout << "▔";
        cout << endl;
    }
    bool isOk(int r, int c)//判断在r行c列放置是否可以满足要求
    {
        int leftup = c - 1, rightup = c + 1;
        for(int i = r - 1; i >= 0; --i)//逐行向上考察每一行
        {
            if(result[i] == c)//第i行的c列有棋子吗
                return false;
            if(leftup >= 0)//考察左上对角线
            {
                if(result[i] == leftup)//第i行leftup列有棋子吗
                    return false;
            }
            if(rightup < 8)//考察右上对角线
            {
                if(result[i] == rightup)//第i行rightup列有棋子吗
                    return false;
            }
            --leftup; ++rightup;
        }
        return true;
    }
public:
    int kinds;  //可行布局种类
    EightQueen():kinds(0){}
    void cal8queens(int row)    //调用方式cal8queens(0)
    {
        if(row == 8)    //8个棋子都放置好了,打印结果
        {
            kinds++;
            cout << "第" << kinds << "种放法:" << endl;
            printQueens(result);
            return;//都放置好了,没法再递归了
        }
        for(int column = 0; column < 8; ++column)//每行有8种放法
        {
            if(isOk(row,column))    //该放法满足要求
            {
                result[row] = column;//第row行的棋子放到了column列
                cal8queens(row+1);  //考察下一行
            }
        }
    }

};
int main()
{
    EightQueen eq;
    eq.cal8queens(0);
    cout << "共有" << eq.kinds << "种摆放方法。" << endl;
    return 0;
}

在这里插入图片描述

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
八皇后问题是一个经典的回溯算法问题,在C语言中可以通过递归实现。以下是一个简单的示例代码: ```c #include <stdio.h> #define N 8 int board[N][N]; // 检查当前位置是否可以放置皇后 int isSafe(int row, int col) { int i, j; // 检查当前列是否有其他皇后 for (i = 0; i < row; i++) { if (board[i][col] == 1) { return 0; } } // 检查左上方对角线是否有其他皇后 for (i = row, j = col; i >= 0 && j >= 0; i--, j--) { if (board[i][j] == 1) { return 0; } } // 检查右上方对角线是否有其他皇后 for (i = row, j = col; i >= 0 && j < N; i--, j++) { if (board[i][j] == 1) { return 0; } } return 1; } // 解决八皇后问题的递归函数 int solveNQueens(int row) { int col; // 所有行都已经放置好皇后,打印结果 if (row == N) { printf("解决方案:\n"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { printf("%d ", board[i][j]); } printf("\n"); } printf("\n"); return 1; } // 尝试放置皇后在当前行的每一列 for (col = 0; col < N; col++) { if (isSafe(row, col)) { // 放置皇后 board[row][col] = 1; // 递归处理下一行 solveNQueens(row + 1); // 回溯,撤销当前位置的皇后 board[row][col] = 0; } } return 0; } int main() { // 初始化棋盘 for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { board[i][j] = 0; } } solveNQueens(0); return 0; } ``` 这个代码会输出所有可能的八皇后问题解决方案。每个解决方案都会以矩阵形式打印出来,其中1代表皇后的位置,0代表空格。你可以根据需要对代码进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael阿明

如果可以,请点赞留言支持我哦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值