N皇后问题 (简单回溯)

问题描述:

在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。

输入:

共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。

输出:

共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。

Sample Input

1
8
5
0

Sample Output

1
92
10

【思路】:数据量很小可直接暴力回溯即可,优化的话可以开个vis数组来标记一下之前放的皇后。直接从n*n的棋盘的第一行开始向下方即可,以下代码从0开始所以我写的是从第0行开始搜。先说一下回溯的条件,也就是结束“叶子节点”(我把最深层的那行称为叶子节点)递归的条件,也就是当k(你当前的行数)能搜到第n行时也就是一个超出棋盘的下一行时便可以进行回溯。

然后如果不满足结束条件,则自己假设将皇后放在改行的每列上看看放在哪几个列上可行。这里注意不满足的条件,因为每行只可能放一个皇后所以只需要判断,是否在一列,左斜线,右斜线即可。切记,左斜线时不可求绝对值,直接两个坐标相减判相等即可。如若加绝对值,则对角线右上方的和左下方的情况会混。所以直接利用坐标特点判断即可,不明白的可以直接自己画一个空白坐标系,看一看在同一斜线上的点的纵坐标和横坐标的关系,不难看出。

以下给出代码。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>

using namespace std;
#define LL long long

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const int M = 1e9 + 7;
int a[20];
int cnt,n;//n为n个皇后 棋盘大小为n*n cnt代表多少种放置方法

void f(int k)//一行一行的递归 然后进行回溯
{
    if(k>=n){
//只要把棋盘都放完即可 即结束递归的条件就是传入的值比棋盘行数大一 我这从0开始所以等于n就可
        cnt++;
        return ;
    }
    else
    {
        for(int i=0;i<n;i++){
            bool flag = false;
            a[k] = i;//在第k行i列上
            for(int j=0;j < k;j++){//看是否出现皇后的冲突 和已经放上的判断 就判断那三个条件
                    //不可求绝对值 不然在对角线右上方和左下方的情况会判断错误 刚刚脑子一懵添了个绝对值 
                if(a[j]==a[k]||(j-a[j])==(k-a[k])||(a[k]+k)==(a[j]+j))//判断是否在一列 左斜 右斜
                {
                    flag = true;
                    break;
                }
                   /*if((a[j]==a[k])||(abs(k-j)==abs(a[j]-a[k]))){//如果这样的话是可以加绝对值来表示两点共线的 y2-y1/(x2-x1)=+1/-1;
                    flag = true;
                    break;
                }*/
            }
            if(flag==false)
            {
                f(k+1);
            }
        }
    }
}


int main(){

    while(cin>>n){
        if(n==0)
            break;
        cnt = 0;
        f(0);//从第0行开始递归 先在棋盘第一行放入一个皇后
        cout<<cnt<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Puppet__/article/details/83104411
今日推荐