n皇后问题(dfs搜索回溯+标记)

洛谷的一道类似的n皇后题:P1219 八皇后

题目:n皇后问题

Description

在n×n 格的棋盘上放置彼此不受攻击的n 个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何两个皇后不放在同一行或同一列或同一斜线上。

设计一个解n皇后问题的队列式分支限界法,计算在n×n个方格上放置彼此不受攻击的n个皇后的一个放置方案。

注意,本问题的答案可能是不唯一的。如,当n=5时,至少有3个答案:
在这里插入图片描述

Input
输入一行,一个正整数n。 4 < n < 13

Output
输出彼此不受攻击的n个皇后的一个放置方案。

Sample Input
5

Sample Output
1 3 5 2 4

#include<iostream>
using namespace std;
///用四个数组分别去标记行,列,斜上,斜下,注意斜上和斜下的数组要开成行列数组的两倍
bool hang[15],lie[15],xieshang[30],xiexia[30];
int ans[15],k,n,sum;
void dfs(int i)
{
    if(sum==1)return; ///当已经搜索到一个方案后,便会一直放回到主函数,不再搜索下去了
    if(i==n+1){
        for(int d=1;d<=k;d++)cout<<ans[d]<<' ';
            cout<<endl;
        sum++;
        return;
    }
    for(int j=1;j<=n;j++){
        if((!hang[i])&&(!lie[j])&&(!xieshang[i+j-1])&&(!xiexia[i-j+n])){
            hang[i]=1,lie[j]=1,xieshang[i+j-1]=1,xiexia[i-j+n]=1;
            ans[++k]=j;
            dfs(i+1);
            k--;
            hang[i]=0,lie[j]=0,xieshang[i+j-1]=0,xiexia[i-j+n]=0;
        }
    }
    return;
}
int main()
{
    cin>>n;
    dfs(1);
    //cout<<sum<<endl; 此时这里的输出结果是sum=1
    return 0;
}

题目:2n皇后问题

Description

给定一个n×n ( 0 < n ≤ 8 )的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?

Input
多测试用例,每个测试用例:
第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数。
如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后

Output
每个测试用例输出一行:一个整数,表示总共有多少种放法。

Sample Input
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1

Sample Output
2
0

分析:

先放完一种颜色的皇后之后再去放另一种颜色的皇后(如:先放完白皇后之后再去放黑皇后),做法是在n皇后的基础上再加一个dfs去搜索另一颜色皇后的摆放方法就行了。

代码如下:

#include<iostream>
using namespace std;
bool hang[10],lie[10],xieshang[20],xiexia[20];///白皇后的四个方向标记数组
bool hang2[10],lie2[10],xieshang2[20],xiexia2[20]; ///黑皇后的四个方向标记数组
int G[10][10],n,sum;
void dfs_black(int i)///黑皇后
{
     if(i==n+1){
        sum++;
        return;
    }
    for(int j=1;j<=n;j++){
        if((!hang2[i])&&(!lie2[j])&&(!xieshang2[i+j-1])&&(!xiexia2[i-j+n])&&G[i][j]){
            hang2[i]=1,lie2[j]=1,xieshang2[i+j-1]=1,xiexia2[i-j+n]=1;
            dfs_black(i+1);
            hang2[i]=0,lie2[j]=0,xieshang2[i+j-1]=0,xiexia2[i-j+n]=0;
        }
    }
    return;
}
void dfs_white(int i)///白皇后
{
    if(i==n+1){
    	/*白皇后摆放完之后再去摆放黑皇后*/
        dfs_black(1);
        return;
    }
    for(int j=1;j<=n;j++){
        if((!hang[i])&&(!lie[j])&&(!xieshang[i+j-1])&&(!xiexia[i-j+n])&&G[i][j]){
            hang[i]=1,lie[j]=1,xieshang[i+j-1]=1,xiexia[i-j+n]=1;
            G[i][j]=0;///表示该位置已被白皇后摆放,之后摆放黑皇后就不能再摆放在该位置
            dfs_white(i+1);
            G[i][j]=1;
            hang[i]=0,lie[j]=0,xieshang[i+j-1]=0,xiexia[i-j+n]=0;
        }
    }
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    while(!(cin>>n).eof())
    {
        sum=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                cin>>G[i][j];
        dfs_white(1);///先摆放白皇后
        cout<<sum<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值