2n皇后问题

问题描述

  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
  输入的第一行为一个整数n,表示棋盘的大小
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2

首先考虑n皇后问题,用回溯法(dfs)
int n; 
int vis[8][8];//记录是否放皇后
void dfs(int i) {
    int j, k;
    if (i == n) {
        return;
    }
    for (j = 0; j < n; j++) {
        int flag = 1;//皇后不冲突
        if (vis[i][j] != 1) continue;
        for (k = 0; k < 8; k++)//判断该列列
            if (vis[k][j] == 2) flag = 0;
        for (k = 1; i - k >= 0 && j - k >= 0; k++)//判断左上线
            if (vis[i - k][j - k] == 2)flag = 0;
        for (k = 1; i - k >= 0 && j + k < 8; k++)//判断右上线
            if (vis[i - k][j + k] == 2)flag = 0;
        if (flag == 1) {
            vis[i][j] = 1;//标记皇后
            dfs(i + 1);//判断下一行
            vis[i][j] = 0;//取消标记
        }
    }
}

在白皇后成立的基础上,考虑黑皇后,因此在dfs1中判断条件应做修改:

if (flag == 1) {
    vis[i][j] = 2;//白皇后标记为2
    dfs(i + 1);
    vis[i][j] = 1;//空格标记为1,0的地方跳过
}

当(i==n)即白皇后都放完后,进行dfs2,方法同dfs1,黑皇后标记为3即可


AC代码

#include <iostream>
using namespace std;
int vis[8][8], n,ans=0;
void dfs2(int i) {
    int j, k;
    if (i == n) {
        ans++;
        return;
    }
    for (j = 0; j < n; j++) {
        int flag = 1;
        if (vis[i][j] != 1) continue;
        for (k = 0; k < 8; k++)//
            if (vis[k][j] == 3) flag = 0;
        for (k = 1; i - k >= 0 && j - k >= 0; k++)//左上线
            if (vis[i - k][j - k] == 3)flag = 0;
        for (k = 1; i - k >= 0 && j + k < 8; k++)//右上线
            if (vis[i - k][j + k] == 3)flag = 0;
        if (flag == 1) {
            vis[i][j] = 3;
            dfs2(i + 1);
            vis[i][j] = 1;
        }
    }
}
void dfs(int i) {
    int j, k;
    if (i == n) {
        dfs2(0);
        return;
    }
    for (j = 0; j < n; j++) {
        int flag = 1;
        if (vis[i][j] != 1) continue;
        for (k = 0; k < 8; k++)//
            if (vis[k][j] ==2) flag = 0;
        for (k = 1; i - k >= 0 && j - k >= 0; k++)//左上线
            if (vis[i - k][j - k] ==2)flag = 0;
        for (k = 1; i - k >= 0 && j + k < 8; k++)//右上线
            if (vis[i - k][j + k] == 2)flag = 0;
        if (flag == 1) {
            vis[i][j] = 2;
            dfs(i + 1);
            vis[i][j] = 1;
        }
    }
}
int main() {
    int i,j; cin >> n;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            cin >> vis[i][j];
    dfs(0);
    cout << ans;
    return 0;
}

 

posted @ 2020-09-21 16:52  spider-lily  阅读(105)  评论(0)    收藏  举报
/* 点击爆炸效果*/