题解 P1219 【八皇后】

ybb756032937

2017-12-24 17:33:51

题解

c++搜索与回溯

基本思路:搜索 标记 AC

#include<iostream>//个人不建议采用头文件,可能和定义的变量或名字起冲突,从而引起编译错误;
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
int a[100],b[100],c[100],d[100];
//a数组表示的是行;
//b数组表示的是列;
//c表示的是左下到右上的对角线;
//d表示的是左上到右下的对角线;
int total;//总数:记录解的总数
int n;//输入的数,即N*N的格子,全局变量,搜索中要用
int print()
{
    if(total<=2)//保证只输出前三个解,如果解超出三个就不再输出,但后面的total还需要继续叠加
    {
        for(int k=1;k<=n;k++)
        cout<<a[k]<<" ";//for语句输出
        cout<<endl;
    }
    total++;//total既是总数,也是前三个排列的判断
}
void queen(int i)//搜索与回溯主体
{
    if(i>n)
    {
        print();//输出函数,自己写的
        return;
    }
    else
    {
        for(int j=1;j<=n;j++)//尝试可能的位置
        {
            if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))//如果没有皇后占领,执行以下程序
            {
                a[i]=j;//标记i排是第j个
                b[j]=1;//宣布占领纵列
                c[i+j]=1;
                d[i-j+n]=1;
                //宣布占领两条对角线
                queen(i+1);//进一步搜索,下一个皇后
                b[j]=0;
                c[i+j]=0;
                d[i-j+n]=0;
                //(回到上一步)清除标记
            }
        }
    }
}
int main()
{    
    cin>>n;//输入N*N网格,n已在全局中定义
    queen(1);//第一个皇后
    cout<<total;//输出可能的总数
    return 0;
}

注释:对角线d[i-j]后面必须加上一个n,因为i-j可能为负数,那么数组就会出错,所以将整体向右偏移n个单位(坐标偏移不会影响我们需要达到的目的),将所有可能变成正数;(因为i-j的最小值是-n+1,所以加上一个n就一定会变成一个正数)

本道题最重要的就是记录下皇后占领的格子(打标记的思想),通过此判断下一个皇后是否可以在某个位置,如果可以,则继续搜索下一个皇后可以在的位置,如果不行,则清除标记回到上一步,继续搜索;

可以先考虑六个皇后(即6*6网格),再将6改为n,并且输入n,就可以得出6到13个皇后的解了;