N皇后问题

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个1
  • pos&(-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;
}
点赞