算法练习题13---N皇后问题


前言

N皇后问题是非常经典的回溯和剪枝的应用,也是数据结构与算法课程中非常重要的一个算法思想。它一般采用DFS也称深度优先搜索算法来解决。通过一道例题来具体介绍一下这类题目的解法和其算法思想。

一、题目描述

题目为 hdu2553 “N皇后问题”

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

输入

共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。

输出

共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。

样例输入

1

8

5

0

样例输出

1

92

10

二、思路

以四皇后问题为例,从第一行开始放皇后,第1行从左到右有4种方案,产生4个子状态,从这4个子状态出发,又能展开6种相同深度的子状态,依次递归下去,直到把图填满。这里展开的过程虽然像是BFS,但实际上在DFS中,是将一种子状态一直向深遍历到结果或遇到错误情况,才会回退。

那么判断错误的条件是什么?

设已经放好的皇后坐标是(i ,j),当前要判断的坐标是(c,r)

  • 行不相同,即i!=r
  • 列不相同,即j!=c
  • 还有斜对角线不相同,有(i-a,j-a),(i+a,j-a),(i-a,j+a),(i+a,j+a)四种情况,那么(i,j)点在各自移动a的距离后,产生了上述的四种条件下,我们其实可以把情况概括为c与i,和r与j点的距离不能是a,那么就是abs(i - r)!=abs(j - c)

其他的部分通过阅读代码就可以很好理解了

三、代码实现

#include<bits/stdc++.h>
using namespace std;
int col[15]={0};
int tot;
int n;
bool check(int c,int r) //该行用来检查是否与之前放好的皇后有冲突
{
	for(int i=0;i<r;i++)  //遍历当前行之前的情况
	{
		if(col[i]==c||abs(col[i]-c)==abs(i-r))
		{
			return false;
		}
	}
	return true;
}

void dfs(int r)  //一行一行地放皇后,这次是第r行
{
	if(r==n)  //遍历完所有的0~n-1的情况,进入到n层中,说明已经符合要求
	{
		tot++;
		return;
	}
	for(int c=0;c<n;c++)  //在每一列放皇后
	{
		if(check(c,r))  //check通过,可以在此处安放
		{
			col[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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨大熊的代码世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值