题目 HDU 2553“N皇后问题”
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2553
前言:
通过这个题学习到了剪枝。暴力破解会超时啊,就很拿人。DFS的难点在于扩展子节点的时候如何构造停止递归并返回的条件,就要用到剪枝函数。
依然举个例子,分析一下4皇后怎么搞。
思路如下:
从第一行开始放皇后:第一行从左到右有4种方案,产生4个结点;第2行,排除同列和斜线,拓展新的结点,注意不用排除同行,因为第二行和第一行已经是不同行的了。继续拓展第三行和第四行,结束。
下面上分析图:
这下应该很明白了吧!
这个题其实用BFS和DFS都可以写,但是DFS毕竟比BFS代码量更少。
算法分析:
设左上角是原点(0,0),已经放好的皇后的坐标是(i,j),不同行不同列不同斜线的新皇后的坐标是(r,c)那么:
1、横向,不同行:i≠r
2、纵向,不同列:j≠c
3、斜对角:从(i,j)向斜对角方向走a步,那么新坐标(r,c)有4种情况,即左上(i-a,j-a)右上(i+a,j-a)左下(i-a,j+a)右下(i+a,j+a)综合起来就是|i-r|=|j-c|新皇后的位置不能放在斜线上,需要满足|i-r|≠|j-c|
这个题注意是N<=10,如果N>11需要用位运算/数据结构舞蹈链,这也仅仅是到N=15,如果N再大就是NP问题了
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,tot = 0;
int col[12] = {0};
bool check(int c,int r){//检查是否和已经放好的皇后冲突
for(int i;i<r;i++)
if(col[i] == c||(abs(col[i]-c) == abs(i-r)))//取绝对值
return false;
return true;
}
void dfs(int r){//一行一行放皇后
if(r == n){//所有皇后都放好了,递归返回
tot++;
return;
}
for(int c = 0;c<n;c++)//在每一列放皇后
if(check(c,r)){//检查是都合法
col[r] = c;//在第r行的第c列放皇后
dfs(r+1);//继续放下一行皇后
}
}
int main(){
int ans[12] = {0};
for(n = 0;n<=10;n++){//算出所有N皇后的答案,注意先打表,不然会超时
memset(col,0,sizeof(col));//清空,准备计算下一个N皇后问题
tot = 0;
dfs(0);
ans[n] = tot;//打表
}
while(cin>>n){
if(n == 0)
return 0;
cout<<ans[n]<<endl;
}
return 0;
}
细节处理:
1、打表。在main()中提前算出了从1到10的所有N皇后的问题的答案,并存储在数组中,等读取输入后立刻输出。如果不打表,会超时的!
2、回溯判断check()仅仅需要判断纵向和对角线方向,因为在递归是已经是按照不同的行放置的。