全排列
排列即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;