P1219——[USACO1.5]八皇后 Checker Challenge——递归/回溯算法

P1219——[USACO1.5]八皇后 Checker Challenge——递归/回溯算法

题目描述

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

img

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

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

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

输入格式

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

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

输入输出样例

输入 1

6

输出 1

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

说明/提示

【数据范围】
对于 100%100% 的数据,6≤ n ≤13。

题解/思路:

惯例,先吐槽一下我自个的憨:题目描述中的图,行列是从1开始,如 6x6 ,然后我这个憨憨,写的时候考虑到使用数组,我就从0开始写的,然后试样例的时候,我发现我的运行结果和样例差很远,人都傻了。(也没卡多久,也就半把个小时吧,害)

解题思路:

题目大意如下:放置棋子的位置所在的行,列,与主对角线/副对角线平行的线所在的位置均不能有棋子与之冲突

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRbLsXzD-1609936295865)(C:\Users\happy\AppData\Roaming\Typora\typora-user-images\image-20210106195944498.png)]

解题思路基本上写在代码中了,这里再解释一个东西,即对主对角线/副对角线和其平行线出位置的判断:

主对角线:行号减列号,由于用数组存数,所以再加上 n-1,如下图就加上5(6-1),

副对角线类似,为了与主对角线区别,所以,以 行号加列号 进行记录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UjvEQP9q-1609936295867)(C:\Users\happy\AppData\Roaming\Typora\typora-user-images\image-20210106201901351.png)]

噢,还有由于题目要求,只用输出前三组,所以在输出的时候记得做一个小判断噢,顺便贴一下,小破站讲八皇后问题讲的很好的(我觉得)一个视频:https://www.bilibili.com/video/BV1wJ411U7Gy?p=1&share_medium=android&share_plat=android&share_source=QQ&share_tag=s_i&timestamp=1609919821&unique_k=ZscPxK

代码如下:

#include <bits/stdc++.h>

using namespace std;
int place[13]={
    
    0};//第n个皇后所占位置的列号
bool flag[13]={
    
    1,1,1,1,1,1,1,1,1,1,1,1,1};//标志数组,表示第col列是否可占,1表示可占领
bool d1[25]={
    
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//主对角线是否被占领的标记,行列相减再加n-1
bool d2[25]={
    
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//副对角线是否被占领的标记,行列相加
int number=0;//统计解的数量

void King(int a,int n);

int main()
{
    
    
    int n;
    cin>>n;
    King(0,n);
    cout<<number<<endl;
    return 0;
}

void King(int a,int n)
{
    
    
    int col;
    for(col=0;col<n;col++)
    {
    
    
        if(flag[col] && d1[a-col+(n-1)] && d2[a+col])
        {
    
    
            place[a]=col;//在a行col列放置皇后
            //宣布占领
            flag[col] = false;
            d1[a-col+(n-1)] = false;
            d2[a+col] = false;
            if(a<(n-1))//第col行,放置之后,继续考虑这一行的下一行
                King(a+1,n);//递归
            else//n个皇后都被放完了,打印结果
            {
    
    
                number++;
                if(number<=3)
                {
    
    
                    for(int i=0;i<n;i++)
                    {
    
    
                        cout<<place[i]+1<<' ';//俺从0行0列开始的,所以需要在输出的时候+1
                    }
                    cout<<endl;
                }
            }
            //棋盘复原,考虑其他情况,回溯(这个真的好难,呜呜)
            flag[col] = true;//(1为ture,0为false)
            d1[a-col+(n-1)] = true;
            d2[a+col] = true;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/m0_51344172/article/details/112297219