HDU 2553 N皇后问题(回溯 + 剪枝)

本文链接:http://i.cnblogs.com/EditPosts.aspx?postid=5398797

题意:

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

思路:

  回溯 + 剪枝,有点类似于DFS全排列。利用emp[i]表示从左往右第 i 个皇后的所在的行,从而使得所有皇后默认不在同一列。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int MAXN = 23;
int emp[MAXN];  //emp[i] 表示从左往右 第 i 个皇后所在的行
int used[MAXN];  //标记这一行已经被使用
int n;
int cnt;    //合理的解的总数

int check(int key)  //判断第 key 个皇后的位置是否合理
{
    if(used[ emp[key] ])  //判断 行 是否合理
        return 0;
    for(int i = 1; i < key; i++) // 判断斜着是否和合理
        if( abs(i - key) == abs(emp[i] - emp[key]) )
            return 0;
    return 1;
}

void backtrack(int key)  
{
    if(key > n) //满足条件的一个解
        cnt++;
    else
    {
        for(int i = 1; i <= n; i++)  //第 key 列的皇后可以有放到 1 - N 行的N种选择(状态)
        {
            emp[key] = i;     //把第 key 个皇后放在第 i 行
            if(check( key )) //合法性
            { 
                used[i] = 1; //标记这 行 已被使用
                backtrack( key + 1); // 继续求解下一个皇后
                used[i] = 0; //恢复现场
            }
        }
    }
}

int main()
{
    //freopen("out.txt", "w", stdout);
    while(cin >> n)
    {
        cnt = 0;
        memset(emp, 0, sizeof(emp));
        memset(used, 0, sizeof(used));
        backtrack(1);  //从第一个皇后开始放
    }
    return 0;
}

 

posted @ 2016-04-16 17:05  vrsashly  阅读(520)  评论(0编辑  收藏  举报