您的位置:首页 > 其它

全排列——内容整理

2013-11-11 02:56 351 查看
1.生成1-n的全排列:

代码:

#include<stdio.h>
int A[100];
void print_permutation(int n, int* A, int cur)
{
int i, j;
if(cur == n)// 递归边界;
{
for(i = 0; i < n; i++) printf("%d ", A[i]);
printf("\n");
}
else
{
for(i = 1; i <= n; i++)// 尝试在A[cur]中填各种整数i
{
int ok = 1;
for(j = 0; j < cur; j++)
if(A[j] == i) ok = 0; // 如果i已经在A[0]~A[cur-1]出现过,则不能再选
if(ok)
{
A[cur] = i;
print_permutation(n, A, cur + 1); // 递归调用
}//if
}//for
}//else
}
int main(void)
{
print_permutation(4, A, 0);
return 0;
}

结果:



优化一(增加一个标记数组):

void permutation(int cur,int n)
{
int i;
if(cur == n)
{ // 递归边界
sum++;
for(i = 1; i < n; i++) printf("%d ", a[i]);
printf("\n");
}
else
for(i = 1; i < n; i++)
{
if(vis[i] == 0)
{
a[cur] = i;
vis[i] = 1;//选
permutation(cur + 1, n);
vis[i] = 0;//不选
}//if
}//for
}
完整代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_N 10
int n;//共n个数
int rcd[MAX_N];//记录每个位置填的数
int used[MAX_N];//标记每个数是否用过;
int num[MAX_N];//存放输入的n个数;
void full_permutation(int cur)
{
int i;
if(cur == n)
{
for(i = 0; i < n; i++)
{
printf("%d", rcd[i]);
}
printf("\n");
return ;
}
for(i = 0; i < n; i++)//枚举所有的数(n个), 循环从开始
{
if(!used[i])//若num[i]没有使用过,则标记为已使用
{
used[i] = 1;
rcd[cur] = num[i];//在cur位置上放上该数
full_permutation(cur + 1);//填下一个位置
used[i] = 0;//清标记
}
}
}
int main(void)
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d",&num[i]);
}
full_permutation(0);
return 0;
}
//程序通过 used数组,标记数是否被用过,可以产生全排列,共n!种。
//但是通过观察会发现,若输入的n个数有重复,那么在输出n!种排列
//中,必然存在重复的项。


2.生成可重集的全排列:
若问题为:
输入数组P,并按字典序输出数组A各元素的所有全排列。
则需要对上述程序进行修改:
(1).把P添加到printf_permutation的参数列表中, 然后把代码中的if(A[j] == i) 和 A[cur] = i改成if(A[i] == P[i]) 和A[cur] == P[i];
(2).P的所有元素按照从小到大排序;
(3).对于处理1 1 1这种情况,统计A[0] ~A[cur - 1]中P[i]出现的次数c1,以及P数组中P[i]出现的次数c2.只要c1 < c2,就能调用递归;
(4).对于(3)中的那种情况,进行了上述处理后,只是有结果输出了,但是会输出27个1 1 1,遗漏倒是没有, 可是出现了重复。对此,我们应该知道,我们枚举的下标是应该不重复、不遗漏地取遍所有P[i]值,由于P数组已经排过序了,所以只需检查P的第一个元素和所有“与前一个元素不相同”的元素,即只需在for循环和后面的花括号之间加上if(!i || P[i] != P[i - 1])即可。
代码:
#include<stdio.h>
int P[100], A[100];
void print_permutation(int n, int* P, int* A, int cur)
{
int i, j;
if(cur == n)
{
for(i = 0; i < n; i++)
printf("%d ", A[i]);
printf("\n");
}
else
{
for(i = 0; i < n; i++)
if(!i || P[i] != P[i-1])
{
int c1 = 0, c2 = 0;
for(j = 0; j < cur; j++) if(A[j] == P[i]) c1++;
for(j = 0; j < n; j++) if(P[i] == P[j]) c2++;
if(c1 < c2)
{
A[cur] = P[i];
print_permutation(n, P, A, cur+1);
}//if
}//if
}//else
}
int main(void)
{
int i, n;
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &P[i]);
print_permutation(n, P, A, 0);
return 0;
}


结果:





3.下一个排列:

这是枚举的另一个方法:从字典序最小排列开始,不停地调用“求下一个排列”的过程。

如何求下一个排列?

C++的STL中提供了一个库函数next_permutation。

代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
int main(void)
{
int n, p[10];
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &p[i]);
sort(p, p+n); // 排序,得到p的最小排列
do
{
for(int i = 0; i < n; i++)
printf("%d ", p[i]); // 输出排列p
printf("\n");
}while(next_permutation(p, p + n)); // 求下一个排列
return 0;
}
结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: