全排列与n皇后

全排列

排列即n个整数按照一定的顺序摆放的结果是一个排列,全排列就是n个整数能得到的所有排列。例如1,2,3全排列为(1,2,3)( 1,3,2) (2,1,3) (2,3,1) (3,1,2) (3,2,1)

我们可以定义一个数组arrange[maxn]记录要输出的排列结果,利用一个哈希数组hashTable[maxn]记录已经放在arrange[maxn]中。

可以使用递归的方法实现

#include <cstdio>
const int maxn = 100;
int n;
int arrange[maxn], hashTable[maxn] = { 0 };
void generateP(int index)
{
	if (n+1 == index)//递归边界 一共n个数当index超过n时,说明n个数都已经全部放在记录排列的数组当中了
	{
		for (int i = 1; i <= n; i++)//输出排列
		{
			printf("%d ", arrange[i]);
		}
		printf("\n");
	}
	for (int x = 1; x <= n; x++)//遍历将n个数放入arrange[]数组中
	{
		if (hashTable[x] == 0)//找到当前未放入到排列当中的x
		{
			arrange[index] = x;//将x放入到数组中的第index位置,此时0~index位置都已放入数字
			hashTable[x] = 1;//x已放入arrange[]中
			generateP(index + 1);//排列第index+1位置
			hashTable[x] = 0;//已经处理完arrange[index]为x的子问题,还原状态
		}
	}
}
int main()
{
	while (scanf("%d", &n) != EOF)
	{
		generateP(1);
	}
	return 0;
}

 输入3 

 

n皇后

n*n的国际象棋棋盘上n个皇后进行摆放,n个皇后两两均不在同一行,同一列,同一条对角线上,求合法的方案数

例:图中可以看作一个二维数组,按照行数个每个皇后标记可以看到2 5在同一对角线上,5的坐标(5,2)2坐标(2,5);

显然两点在对角线上时,横坐标纵坐标差值相等

全排列可以排除同一行,同一列,对排列进行修改消除同一对角线情况即为n皇后结果

  1  
    2
3    
   4 
 5   

对全排列递归进行修改

int count=0;//全局变量
if (n+1 == index)//递归边界 一共n个数当index超过n时,说明n个数都已经全部放在记录排列的数组当中了
	{
        int flag=1;
		for (int i = 1; i <= n; i++)//列
		{
			for(int j=i+1;j<=n;j++)//列arrange[j]行
            {
                 if(abs(i-j))==abs(arrange[i]-arrange[j]));
                       flag=0;
            }
		} 
            if(flag==1)  count++;
            return;
	}

完整:

#include <cstdio>
#include <cmath>
const int maxn = 100;
int n;
int arrange[maxn], hashTable[maxn] = { 0 };
int count = 0;
void generateP(int index)
{
	if (index == n + 1)
	{
		int flag = 1;
		for (int i = 1; i <= n; i++)
		{
			for (int j = i + 1; j <= n; j++)
			{
				if (abs(i - j) == abs(arrange[i] - arrange[j]))//abs函数是求整数的绝对值
				{
					flag = 0;
				} 
			}
		}
		if (flag == 1)
		{
			count++;
		}
		return;
	}
	for (int x = 1; x <= n; x++)
	{
		if (hashTable[x] == 0)
		{
			arrange[index] = x;
			hashTable[x] = 1;
			generateP(index + 1);
			hashTable[x] = 0;
		}
	}
}
int main()//案例
{
	n = 8;
	generateP(1);
	printf("%d\n", count);
	return 0;
}

上面的n皇后需要判断所有排列的情况时间复杂度为O(N!),因为n个整数的全排列有n!种

可以在递归过程中进行判断,如果结果冲突,直接返回上一层,这样可以减少更多计算量

#include <cstdio>
#include <cmath>
const int maxn = 100;
int n;
int arrange[maxn], hashTable[maxn] = { 0 };
int count = 0;
void generateP(int index)
{
	if (n + 1 == index)//能都进行到这一步的一定满足条件
	{
		count++;
		return;
	}
	for (int x = 1; x <= n; x++)
	{
		if (hashTable[x] == 0)//判断当前index位置(将要放置x的位置)与已经放置的数的位置是否满足条件
			                  //index之前的已经都满足条件
		{
			int flag = 1;
			for (int k = 1; k < index; k++)//当前x的坐标为(index,x) 前index个数的坐标为(k,arrange[k])
				                           //或者认为当前x的坐标为(x,index) 前index个数的坐标为(arrange[k],k)
			{
				if (abs(index - k) == abs(x - arrange[k]))
				{
					flag = 0;
					break;
				}
			}
			if (flag == 1)
			{
				arrange[index] = x;
				hashTable[x] = 1;
				generateP(index + 1);
				hashTable[x] = 0;
			}
		}
	}
}
int main()
{
	n = 8;
	generateP(1);
	printf("%d\n", count);
	return 0;
}

当n=8时,结果为92;

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

VictorierJwr

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

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

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

打赏作者

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

抵扣说明:

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

余额充值