N皇后问题

16 篇文章 6 订阅

N皇后问题

咳咳,马上就要考试了,今天重新来复习一下N皇后问题,好好的整理下,嗯嗯,N皇后作为经典的回溯和剪枝应用,还是很好入门的。
行,那就先看题目吧,先把题目意思弄懂。

hdu 2553 “n皇后问题”

题目链接:点我了解题目(这是一个链接)

题目大意:

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

输入样例:

1
8
5
0

输出样例:

1
92
10

  • 咳咳,先看题目哈,题目要求在一个 N * N 的方格里面放置N个皇后,并且这N个皇后不同行、不同列、不同斜线。
  • 不明白?我们来看看图吧,这里我们用四皇后来举个例子!

在这里插入图片描述

  • 我们按照不同行不同列不同斜边的规则对四皇后问题进行依次扩展。
  • 其实当n较小,人工都能算出来,但是当n稍稍大的时候就不是人工能搞的了,对于该图,用BFS和DFS都可以算出来,但是BFS相对于DFS代码过于繁琐,我们就用DFS来解决吧!
  • 那么重点来了,我们要如何在扩展下一次节点的时候去除不符合条件的子节点呢?
  • 接下来我们一步一步来解决!
  • 我们设已经放好的皇后的坐标设置为 (i , j),下一个放置的不同行、不同列、不同斜线的新皇后的坐标为 (r , c)。那么根据不同行、不同列、不同斜线,我们可以建立以下剪枝规则:
  • (1) 不同行,所以每行只有一个皇后,这个也不用写,每行就设置一个皇后就能满足不同行的要求。即:i != r。
  • (2) 不同列,这里要注意以下,要求的是所有的皇后都不同列,所以我们要求,所有设立皇后列都不相同,即:j != c。
  • (2) 不同斜线,我们假设一下,从 (i , j)往斜线走a步,那么新坐标 (r , c)就有四种情况,分别是左上(i-a , j-a)、右上(i+a , j-a)、左下(i-a , j+a)、右下(i+a , j+a),那么我们整合一下就是,abs(i-r)=a 、abs(j-c)=a。那么新皇后不在同一斜线上面,只需要满足:abs(i-r) != abs(j-c)即可。
  • ok,到这里,剪枝规则便建立的差不多了。
  • 然后题目输入输出样例可以看出来,是多组输入,因为对应的每一个N皇后输出的放置方式数量是一个固定的值,所以我们需要进行打表来算,这样可以避免重复运算,大大的降低算法的运行时间。
  • 好滴,放代码!!!
#include<bits/stdc++.h>
using namespace std;
int col[12]={0};  //col数组用于存放第i行第col[i]列放置皇后。
int n,tot = 0;		//设置全局变量,即可不用投值,直接调用
bool check(int r,int c){		//判断新皇后是否和放好的皇后发生冲突。
    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){
    if(r==n){ //因为从0开始,当行数r达到n时,表示已经完成了
        tot++;
        return ;
    }
    for(int c=0;c<n;c++){
        if(check(r,c)){ //判断是否可以放置,可以便放置,否则剪枝。
            col[r]=c;
            dfs(r+1);	//继续放置下一行的新皇后
        }
    }
}
int main(){
    int ans[12]={0};
    for(n=0;n<=10;n++){			 //对n皇后进行打表,然后结果存入ans数组
        memset(col,0,sizeof(col)); 	//每次要进行初始化
        tot=0;
        dfs(0);					//DFS
        ans[n]=tot;				//存放
    }
    while(cin >> n){
        if(n==0)return 0;
        cout << ans[n] << endl;
    }
    return 0;
}
  • 代码很短,却极具有智慧,嘿嘿。
  • 这时候也许有人要问了,这里只是将N皇后的数量给求出来,我要图呢,怎么搞?
  • 这里得说一下哈!
  • 其实也是很简单的,我们直接在dfs里面进行输出就行了,当 r== n 的时候,就表示出现了一个可以放置n个皇后的方法了,那么只要放 r== n 我们进行输出,因为col数组,表示的是,第 i 行第 col[i] 列,那么我们就可以根据col数组,在 r==n的时候进行输出了。
  • 代码如下:
#include<bits/stdc++.h>
using namespace std;
int col[12]={0};
int n,tot = 0;
bool check(int r,int c){
	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){
	if(r==n){			//达成条件即可输出。
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				if(col[i]!=j)cout << " ." ;			//这里只需要根据col数组对j进行判断即可输出皇后了,col数组表示的是第i行第col[i]列放置皇后,那么只需要判断col[i]==j的时候放置皇后即可,其余情况直接不放。
				else cout << " X";
			}
			cout << endl;
		}
		cout << endl;
		cout << "-------------分割线-------------" << endl;
		cout  << endl;
		tot++;
		return ;
	}
	for(int c=0;c<n;c++){
		if(check(r,c)){
			col[r]=c;
			dfs(r+1);
		}
	}
}
int main(){
	while(cin >> n && n){
		memset(col,0,sizeof(col));
		tot=0;
		dfs(0);
		cout << tot << endl;
	}
	return 0;
} 
  • 这样就可以做到输出图了,效果如下:

在这里插入图片描述

  • 咳咳,okok,今天的n皇后就到这里吧。玩去了。。。。。



------------------------------2021/1/10------------------------------

改革尚未成功,同志仍需努力!!!
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

木木不会

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

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

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

打赏作者

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

抵扣说明:

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

余额充值