N皇后问题
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
这里我们的思路应该还是DFS,x代表行,y代表选的列数,每次递归x+1,到最后一行(x==n)开始逐层返回
那么列数有什么要求呢,列数不能是已经选取元素的对角或者上下
这里的判断很巧妙(我自己写的就很繁琐)
if(vis[k]==j||abs(i-k)==abs(vis[k]-j))
vis[k]代表的是k行选中的皇后是j列
我们循环1~x-1行就可以了
对角线判断可以思考思考
注意
这里的测试数据量很大,最后活活TLE,需要直接记下已经计算过的
详情看代码
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define pi acos(-1)
const int inf = 0x3f3f3f3f;
int n;
int vis[15];
int a[15];
bool Yes(int i,int j){
for(int k=0;k<i;k++){
if(vis[k]==j||abs(i-k)==abs(vis[k]-j)){
return false;
}
}
return true;
}
int DFS(int i){
int cnt=0;
if(i==n){
return 1;
}
for(int k=0;k<n;k++){
if(Yes(i,k)){
vis[i]=k;
cnt+=DFS(i+1);
}
}
return cnt;
}
int main()
{
while(~scanf("%d",&n)&&n){
if(!a[n]){
a[n]=DFS(0);
}
printf("%d\n",a[n]);
}
return 0;
}
然后学习了一下这个题目的位运算DFS
主要学习它的思想和位运算的知识吧
upperlim=1; upperlim=(upperlim<<n)-1;
制造n个1pos&(-pos)
取pos的最低位,等同于pos&(~pos+1)
(补码的知识if(row!=upperlim){
row是我们的选择,upperlim就全是1,我们选择过的位数标记为1,满足这个条件代表着一种方案long pos=upperlim&(~(ld|rd|row));
ld代表着通过左对角线已经限制的区域,row是上方限制的,除去这些得到的pos中为1的就是还满足条件可以选择的- 那如果我们没有可以选择的地方了怎么退出呢,
while(pos){
就是这个作用 - 我们怎么把这一行的选择的位数告诉程序,然后改变我们的ld和rd再把这个限制传递下去?
row|p,(ld|p)<<1,(rd|p)>>1
一个左移一位一个右移一位,它很巧妙地把所有对角线选择的放置到了一个数里面,膜
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#define ll long long
#define ull unsigned long long
#define pi acos(-1)
const int inf = 0x3f3f3f3f;
using namespace std;
long upperlim=1;
int cnt=0;
void DFS(long row,long ld,long rd){
if(row!=upperlim){
long pos=upperlim&(~(ld|rd|row));
while(pos){
long p=pos&(-pos);
pos-=p;
DFS(row|p,(ld|p)<<1,(rd|p)>>1);
}
}else{
cnt++;
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n){
cnt=0;
upperlim=1;
upperlim=(upperlim<<n)-1;
DFS(0,0,0);
printf("%d\n",cnt);
}
return 0;
}