n皇后问题的子集树求解与排列树求解

本文介绍了N皇后问题的两种经典求解方法:子集树求解和排列树求解,并给出了具体的C语言实现代码。子集树求解通过递归回溯确保皇后之间互不攻击,排列树求解则利用全排列算法结合约束条件完成任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在n×n棋盘上放彼此不受攻击的n个皇后。
按国际象棋规则,皇后可攻击同行、同列、同一斜线的棋子。

等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

 

可以用一个数组存储每行中的皇后的纵坐标,例如n=8时,X=(4,6,8,2,7,1,3,5)表示第一行的皇后的横坐标为4,

第二行的皇后的横坐标为6,......

比较常用的一种求解办法为通过子集树求解,约束条件为abs(k-j)!=abs(x[j]-x[k]) 并且 x[j]!=x[k]。

其实这个问题也可以描述为n个数字的排列问题,约束条件为abs(k-j)!=abs(x[j]-x[k]),这样该问题就可以用全排列的算法求解。

子集树求解的程序为:

#include <cstdio>
#include <cmath>
int x[20];
int n,count;
int Place(int k)
{
	int j;
	for(j=1;j<k;j++)
		if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
			return 0;
	return 1;
}
void Backtrack(int t)
{
	int i;
	if(t>n) 
	{
		for(i=1;i<=n;i++)
			printf("%d ",x[i]);
		printf("\n");
		count++;
	}
	else
	for(i=1;i<=n;i++) 
	{
		x[t]=i;
		if(Place(t))
			Backtrack(t+1);
    }
}
int main()
{
	printf("请输入n:");
	scanf("%d",&n);
	Backtrack(1);
	printf("共%d组答案\n",count);
	return 0;
}

排列树求解的程序为:

#include <cstdio>
#include <cmath>
int n,count;
int Place(int data[], int k)
{
	int j;
	for(j=1;j<k;j++)
		if(abs(k-j)==abs(data[j]-data[k]))
			return 0;
	return 1;
} 
void swap(int &x, int &y)
{
	int temp;
	temp=x;
	x=y;
	y=temp;
}

void perm(int data[], int k, int n)
{
	int i;
	if(k>n)
	{
		for(i=1;i<=n;i++)
			printf("%d ",data[i]);
		printf("\n");
		count++;
	}
	else
	{
		for(i=k;i<=n;i++)
		{
			swap(data[k],data[i]);
			if(k==1 || Place(data,k))
				perm(data,k+1,n);
			swap(data[i],data[k]);
		}
	}
}
int main()
{
	int i;
	int data[20];
	printf("请输入n:");
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		data[i]=i;
	perm(data,1,n);
	printf("共%d组答案\n",count);
	return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值