N皇后问题(c语言实现)

问题描述:

有一个n*n的棋盘,在这个棋盘中放n个皇后,使得这n个皇后,任意两个皇后不在同一行,同一列,同一条对角线。例如,当n等于4时,有两种摆法。
图
输入只有一个整数n。

思路

如果我们是从这个n*n的棋盘中选取n个方格放皇后,再去判断是否满足条件的话,则效率会非常低,这是一个组合数 ∁ \complement n n ∗ n n \atop n*n nnn,当n等于8时,就要枚举54502232次

方法一:递归暴力法

做这个题之前,我们回想一下字符串全排列,这个和它相似,可以枚举每一行的列数,枚举完一个棋盘后,判断任意两个皇后是否在同一条线上,例如上面的摆法1(2413).这个方法的复杂度为n!

代码
#include<stdio.h>
#include<math.h>
int rank[15];//pos列i行 
bool vis[15];//标记第i行是否走过
int n,cnt=0;
void dfs(int pos){
	if(pos==n+1){
		bool flag=true;
		for(int i=1;i<=n;i++){
			bool flag2=true;
			for(int j=i+1;j<=n;j++){//枚举任意两个皇后 
				if(abs(i-j)==abs(rank[i]-rank[j])){//两个皇后处于一条对角线 
					flag=false;
					flag2=false;
					break;
				}
			}
			if(flag2==false)	break;//如果一个填满情况对角线有两个或以上,则直接跳出循环 
		}
		if(flag)	cnt++;
		return;
	}
	for(int i=1;i<=n;i++){//枚举每一行 
		if(vis[i]==false){//第i行没走过 
			rank[pos]=i;//pos列在i行 
			vis[i]=true;
			dfs(pos+1);//递归下一列 
			vis[i]=false;
		}
	}
}
int main(){
	scanf("%d",&n);
	dfs(1);//从第一列开始枚举 
	printf("%d",cnt);
	return 0;
}
方法二:递归回溯法

上面的方法一是当形成一个n*n的棋盘时,才去判断是否满足条件。
而我们在递归时,可以提前判断是否满足条件,如果不满足,则不用递归下去,返回上一层进行处理,这种方法称为回溯法。这个题是当我们递归的时候就去判断当前的皇后是否和前面的皇后在一条对角线上,如果在一条直线上,就不需要递归下去了,返回上一层;如果不在,就继续递归,下一个继续进行判断,直到满足条件为止。

代码
#include<stdio.h>
#include<math.h>
int rank[20];
bool vis[20];
int n,cnt=0;
void dfs(int pos){
	if(pos==n+1){//递归边界条件 
		cnt++;
		return;
	}
	for(int i=1;i<=n;i++){//枚举每行 
		if(vis[i]==false){
			bool flag=true;
			for(int j=1;j<pos;j++){//枚举pos之前的皇后 
				if(abs(pos-j)==abs(i-rank[j])){
					flag=false;
					break;
				}
			}
			if(flag){
				rank[pos]=i;//pos列在i行 
				vis[i]=true;
				dfs(pos+1); 
				vis[i]=false;
			}
		}
	}
}
int main(){
	scanf("%d",&n);
	dfs(1);
	printf("%d",cnt);
	return 0;
} 
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

星空皓月

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

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

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

打赏作者

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

抵扣说明:

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

余额充值