#1912. 八皇后

本文介绍了八皇后问题的解题思路和AC代码实现。通过使用一维数组表示棋盘状态,利用行、左低右高线和右低左高线的标记判断皇后放置的可行性。在递归过程中,当无法在当前列放置皇后时回溯,直至找到所有可能的解。最终输出所有解及其总数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:

行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6

列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。 并把它们以上面的序列方法输出,解按字典顺序排列。 输出所有的解。最后一行是解的总个数。

输入格式

一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。

输出格式

输出所有解,每个解的两个数字之间用一个空格隔开。最后一行只有一个数字,表示解的总数。

输入数据 1

6

Copy

输出数据 1

2 4 6 1 3 5 
3 6 2 5 1 4 
4 1 5 2 6 3 
5 3 1 6 4 2
4

Copy

提示

【数据范围】 对于 100\%100% 的数据,6 \le n \le 106≤n≤10。

题解 

做这道题,我们要解决如下问题:

  • 如何判断是否在 k 列 i 行可行?
  • 放下一个皇后后,怎么让其所在行,列,两条斜线都不能再次放置另一个皇后?
  • 如果某一列的每一行都无法再次放置皇后,要怎么回溯到上一次?
  • 如果k==8时,输出一个可行解后怎么在查找下一个可行解?
  • -最后我们要怎么退出?

A. 对于①、②问题,我们先要找到一种方式来储存可行解,当然我们也可以用二维数组来模拟棋盘,每放置一个皇后就把这位置标记下来,并把所在行列斜线都标记为false,再进行下一次放置皇后时,根据该行该列是否是 false 来放置。但自习思考这样会造成标记和输出上的麻烦 。为了使问题便于思考和简化代码,我们可以采取以下方法。

  • 用一维数组 col[9] 来表示每列上皇放置的位置,如row[A]=B:代表第 A 列第9行放置了一个皇后。
  • 用 bool row[9],digLeft[16],digRight [16]分别表示每行,左低右高线和右低左高线上是否被禁止放置皇后。如row[A]=false,digLeft[B]=false,digRight[C]=false,表示第 A 行,第B条左低斜线和第C条右高斜线上不能放置皇后。至于列就不用了管它了。通过规律我们可以把 B 和 C 用 k 和 i 表示出来。

B. 对于③,但循环 i=9 时自然会退出回溯到上一次放置皇后,不过我们要额外加一条代码来取消上一次的标记。对于④也是同理。

C. 当我们把所有能够试探的方法试探玩后,k=9,自然就会退出递归。

一切都思考清楚后就可以释放代码了,奥利给!

AC代码

#include <iostream>
using namespace std;
void queen_all(int k,int n);
int col[100]={0},times=0;     //用times来记录一共多少种结果
bool row[100]={0},digLeft[100]={0},digRight[100]={0};
int main()
{
    int n=0;
    cin>>n;
    queen_all(1,n);
    cout<<times;
    return 0;
}
void queen_all(int k,int n)
{
    int i=0;
    for (i=1;i<=n;++i)
    {
        if (row[i]!=1&&digLeft[k+i-1]!=1&&digRight[n+k-i]!=1)
        {
            col[k]=i;
            row[i]=digLeft[k+i-1]=digRight[n+k-i]=1;
            if (k==n)
            {
                for (int j=1;j<=n;++j)
                    cout<<col[j]<<' ';
                cout<<endl;
                ++times;
            }
            else queen_all(k+1,n);
            row[i]=digLeft[k+i-1]=digRight[n+k-i]=0;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值