暑假训练3--2n皇后问题的多种解法

题目 1460: [蓝桥杯][基础练习VIP]2n皇后问题

题目描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入
输入的第一行为一个整数n,表示棋盘的大小。

接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2

递归思路:

// 2n皇后的迭代算法练习
//  为了弥补自己的不足,要对每一种代码掌握透彻
// 基本方法 回溯
/*
我们要明白一点的是n*n皇后都可以看成n次游戏的合成
即在满足一种皇后的放置情况下,放置第二个皇后 
对于皇后问题,使用一维数组可以很容易判断是否当前位置
能够放置,详细请上网查找资料 
*/ 
#include <iostream> 
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
int a[9];  //表示第i行放置白皇后的位置
int Map[9][9]; //保存图盘信息
int b[9];  //表示第i行放置黑皇后的信息 
int n;
// 首先使用递归的思路 
int sum = 0;   //记录方法数 
void Init()
{
	for(int i =0;i<=n;i++)
	{
		a[i] = INF;
		b[i] = INF;
	}
	
	for(int i =1;i<=n;i++)
	 for(int j =1;j<=n;j++)
	 {
	 	cin>>Map[i][j];
	 }
}

bool check1(int row,int col)
{   
    if(Map[row][col]==0) return false;
	for(int i =1;i<row;i++)
	{   
		if(a[i]==col||abs(a[i]-col)==abs(i-row)) return false;  //核心代码 
	}
	return true;
}
bool check2(int row,int col)
{   
    if(Map[row][col]==0) return false;
    if(a[row]==col) return false;
	for(int i =1;i<row;i++)
	{   
		if(b[i]==col||abs(b[i]-col)==abs(i-row)) return false; //核心代码 
	}
	return true;
}

void dfs2(int row)
{
	for(int i = 1;i<=n;i++)
	{
		if(check2(row,i))
		{   
		    b[row] = i;
			if(row==n)
			{
				sum++;
			}
			else
			dfs2(row+1);
		}
	}
	return;
}

void dfs1(int row)
{
	for(int i = 1;i<=n;i++)
	{
		if(check1(row,i))
		{   
		    a[row] = i;
			if(row==n)
			{
				dfs2(1);
			}
			else
			dfs1(row+1);
		}
	}
	return;
}

int main()
{
	cin>>n;
	Init();
	dfs1(1);  //首先从白皇后开始遍历 
	cout<<sum<<endl;
}

使用while语句的迭代核心部分:

void queen1()
{
  int row=1,col= 1;	
  while(row<=n)
  {
     
  	 while(col<=n)
  	 {
  	 	if(check1(row,col))
  	 	{
  	 		a[row] = col;
  	 		col=1;   //从头开始找 
  	 		break;
		}
		else
		col++;
	 }
    if(a[row]==INF)
    {
    	if(row == 1) break; //函数出口
		else
		{
			row--;
			col = a[row]+1;
			a[row] = INF;
			continue;
		 } 
	}
	if(row == n)
	{
		queen2();
		col = a[row]+1;
		a[row] = INF;
		continue;
	}
	row++;
  }
} 

进阶解法:位运算,这里由于是双皇后和有0的问题,所以暂时还没想到如何来解决。不过思想还是要清楚的。

//进阶版本,位预算,速度及其快,但重要的是理解他的本质 
void test1(int row,int ld,int rd)  //分别代表数列,左对角线,右对角线上的禁位 
{
	int pos,p;
	if(row!=upperlim)
	{
		pos = upperlim&(~(row|ld|rd));//取他们能放的位置
		while(pos)
		{
			p = pos&(~pos+1);//p是提取pos最右边能放的位置
			pos = pos -p;   //将他从可放的位置除去
			test1(row|p,(ld|p)<<1,(rd|p)>>1);
		}
	}
	else
	 sum++;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值