JakeLin- [Blue Bridge Cup / ACM] 2n Queen Question / 8 Queen Question-Detailed Solution

Title description

Given an n * n board, there are some positions on the board that cannot be used by the queen. Now we need to put n black queens and n white queens on the chessboard, so that any two black queens are not in the same row, same column or same diagonal, any two white queens are not in the same row, On the same column or on the same diagonal. Ask how many kinds of release methods in total? n is less than or equal to 8. 

Input

The first line of input is an integer n, indicating the size of the chessboard. 

In the next n rows, there are n integers of 0 or 1 in each row. If an integer is 1, it indicates that the corresponding position can be placed as a queen. If an integer is 0, it indicates that the corresponding position cannot be placed as a queen. 

Output

An integer is output, indicating how many kinds of putting methods in total. 

Sample input

4
1 1 1 1 
1 1 1 1 
1 1 1 1 
1 1 1 1 

Sample output

2

Original title link: [Blue Bridge Cup] [Basic Practice VIP] 2n Queen Question

 

Before we study the 2n queen problem, we need to understand a classic question type of backtracking: the eight queen problem


1. First paste the eight queens question:

Given an 8 * 8 board. Now we need to put 8 queens on the board so that any two queens are not in the same row, same column, or on the same diagonal. How many ways are there in total?

We need to be clear:

  • 1. Eight queens will be put in
  • 2. Put one per line (there is only one)
  • 3. There will also be one for each column (and only one)
  • 4. If you use full arrangement or eight for loops, the result is mostly tragic

Key code:

int vis[10];   //vis[i]=1 表示第i【列】被访问过了,后面此列不被访问
int a[10];    //a[i]=j 表示第i个皇后(第i行)的位置为j->a[j]
void dfs(int step,int n) {   //安排第step个皇后(即第step【行】)
    if(step==n+1) {   //递归边界,表示n个皇后已经安排好了
        cnt++;
    } else {
        for(int i=1; i<=n; i++) {   //遍历i列
            if(vis[i]==0) {   //第i列必须是之前没访问过得一列
                bool tag = true;
                for(int j=1; j<step; j++) {   //遍历a数组1~step:查找与之前已经定好位的皇后是否冲突
                    if(step-j == i-a[j] || step-j == a[j]-i) {
                    //当前位置:(step,i)  之前位置(j,a[j]),若他们在对角线上,则斜率(step-j)/(i-a[j])为1或-1
                        tag = false;
                        break;
                    }
                }
                if(tag) {    //  i列符合条件
                    vis[i]=1;  // 访问
                    a[step] = i;
                    dfs(step+1,n);// 安排下一个皇后
                    vis[i]=0;  // 回溯:恢复DFS之前的状态
                }
            }
        }
    }
}

Approximation of the variation of the question type, see the  checkerboard polynomial-problem solution (C / C ++ description)-detailed explanation


Second, the problem of moving to the 2n queen :

The difference is that in addition to a black queen in each row, there will also be a white queen.

Therefore, after finding a location for the black queen according to the above method, we still need to find it once and locate the white queen. Only after the two queens have been arranged can we enter the next line of positioning .
So you will find that whether it is an array of vis or an array of queens, we need to prepare two copies

The complete code is provided below:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int cnt = 0;
int map[10][10]; //存储地图
int visb[10];   //visb[i]=1第i列已经有了黑皇后 
int visw[10];   //白皇后,同上 
int black[10];  //black[i]=j 表示第i个黑皇后(i行)在第j列
int white[10];  //白皇后的位置,同上
void dfs(int step,int n) {  //step代表第几行,要安排第几个皇后
    if(step==n+1) {
        cnt++;
    } else {
        for(int i=1; i<=n; i++) {  //第step行遍历i列(i->1-n)
            bool black_tag = true;
            if(visb[i]==0 && map[step][i]==1) {
                for(int j=1; j<step; j++) { //跟之前已经定好位的皇后做比较
                    if(step-j == i-black[j] || step-j == black[j]-i) {  //斜对角方向 (step,i)和(j,a[j])的斜率为1或-1
                        black_tag = false;
                        break;
                    }
                }
                if(black_tag) {
                    visb[i]=1;  //这一列有皇后了,后面一整列都不能访问
                    black[step] = i;  //(step,i)->(step,a[step])
                    for(int k=1; k<=n; k++) {
                        if(k==i) continue;
                        bool white_tag = true;
                        if(visw[k]==0 && map[step][k]==1) {
                            for(int j=1; j<step; j++) { //跟之前已经定好位的皇后做比较
                                if(step-j == k-white[j] || step-j == white[j]-k) {  //斜对角方向 (step,k)和(j,a[j])的斜率为1或-1
                                    white_tag = false;
                                    break;
                                }
                            }
                            if(white_tag) {
                                visw[k]=1;
                                white[step] = k;
                                dfs(step+1,n);   //搜索下一行(下一个皇后)
                                visw[k]=0;
                            }
                        }
                    }
                    visb[i]=0;
                }
            }
        }
    }
}
int main() {
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            cin>>map[i][j];
        }
    }
    dfs(1,n);
    cout<<cnt;
    return 0;
}

 

 

Published 20 original articles · won 15 · views 216

Guess you like

Origin blog.csdn.net/qq_37414463/article/details/105391466