zoukankan      html  css  js  c++  java
  • 《信息学奥赛一本通》例5.4 八皇后问题 题解

    八皇后问题游戏地址:https://www.brainmetrix.com/8-queens/

    题目描述

    要在国际象棋棋盘((8 imes 8) 的棋盘)中放 (8) 个皇后,使任意两个皇后都不能互相吃。(提示:皇后能吃同一行、同一列、同一对角线的任意棋子。)

    输出格式

    输出一个整数,用于表示八皇后问题的放置方案。

    题目分析

    首先我们用 ((x,y)) 来表示棋盘上第 (x) 行第 (y) 列的格子的坐标。
    那么,两个皇后 ((x_1,y_1))((x_2,y_2)) 会互相攻击当且仅当满足如下条件之一:

    • 在同一行:(x_1 = x_2)
    • 在同一列:(y_1 = y_2)
    • 在同一对角线:(x_1-x_2=y_1-y_2)(x_1-x_2=y_2-y_1) ,化简一下就是坐标差的绝对值相等,即: (vert x_1-x_2 vert = vert y_1-y_2 vert)

    我们可以用深度优先搜索来解决这道题。
    我们可以发现的是,要想在 (8 imes 8) 的棋盘上放置 (8) 个皇后,每一行都必须且只能放置一个皇后,所以我开一个数组 ans[]ans[id] 用于表示在第 id 行放置的皇后的列号。
    然后我开一个函数 f(id) ,用于表示:当前正准备在第 id 行放置一个皇后。然后我从 (1)(8) 去遍历列号 (i) ,如果 ((id,i)) 能放,则我尝试性地在 ((id,i)) 位置放上皇后,然后递归调用 f(id+1) , 直到 id>8 (说明找到了一种放置方案)为止。
    那么,我怎么去判断 ((id,i)) 这个位置能否放置一个皇后呢?我们搜索的顺序是从第 (1) 行一直到第 (8) 行的,所以当我要放置第 (id) 行的皇后的时候,肯定已经在第 (1)(id-1) 行放置好了前 (id-1) 个皇后。所以我只需要从 (1)(id-1) 去遍历行号 (j) ,比较一下第 (j) 行放置的皇后 ((j,ans[j])) 和我现在想要放的皇后 ((id,i)) 是否会相会攻击即可。
    如果这 (id-1) 个皇后都和 ((id,i)) 位置没有冲突,则说明 ((id,i)) 这个位置是可以放的,那我尝试性地在 ((id,i)) 位置放上皇后,并递归地进行下一步搜索 f(id+1)
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    int ans[9], cnt; // ans[i]用于记录第i行皇后列号,cnt用于记录方案数
    // attack函数用于判断(x1,y1)和(x2,y2)两个点是否会互相攻击
    // 返回true:会互相攻击到;返回false:不会互相攻击到
    bool attack(int x1, int y1, int x2, int y2) {
        return x1==x2||y1==y2||abs(x1-x2)==abs(y1-y2);
    }
    // f函数用于在第id行尝试性地放一个i,然后递归地去id+1行放
    void f(int id) {
        if (id > 8) {   // 说明前8行已经放好了
            cnt ++;     // 找到一个方案,cnt++
            return;     // 程序可直接返回
        }
        for (int i = 1; i <= 8; i ++) { // 尝试在第id行第i列放皇后
            bool flag = true;   // flag用于标识是否能放
            for (int j = 1; j < id; j ++) {
                if (attack(id, i, j, ans[j])) { // (id,i)和(j,ans[j])冲突
                    flag = false;              // 将flag设为false标识不能放
                    break;
                }
            }
            if (flag) { // 如果循环结束flag仍为true说明i能放
                ans[id] = i;    // 能放就先放上
                f(id+1);        // 然后递归进行下一行的放置
            }
        }
    }
    int main() {
        f(1);   // 从第1行开始放
        cout << cnt << endl;    // 输出方案数
        return 0;
    }
    
  • 相关阅读:
    在Centos 7下编译openwrt+njit-client
    开博随笔
    Chapter 6. Statements
    Chapter 4. Arrays and Pointers
    Chapter 3. Library Types
    Chapter 2.  Variables and Basic Types
    关于stm32不常用的中断,如何添加, 比如timer10 timer11等
    keil 报错 expected an identifier
    案例分析 串口的地不要接到电源上 会烧掉
    案例分析 CAN OPEN 调试记录 进度
  • 原文地址:https://www.cnblogs.com/quanjun/p/14673082.html
Copyright © 2011-2022 走看看