全排列——内容整理
2013-11-11 02:56
351 查看
1.生成1-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<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; }结果:
相关文章推荐
- 实验 4 在分支循环结构中调用自定义函数
- 程序员必须知道的英语!!
- BIOS和CMOS的联系与区别
- Tomcat密码问题
- C#实现因式分解代码
- 嵌入式面试资料
- 引用 模块编译Makefile模板
- linux下I2C驱动
- osgearth earth文件规范-符号参考
- 0<Double.MIN_VALUE
- 引用 xp系统引导修复(转载)
- JAVA中sleep()、wait()、yield()、join()方法浅析
- 【引用】Linux 内核驱动--多点触摸接口
- 您可能感兴趣的100个网站 按SogouRank排序
- 科研人员常用的十八大学术搜索引擎
- c语言指针数组与数组指针
- 多线程编程技术
- 德国波恩出差记(四)
- Extjs 多表头插件GroupHeaderGrid
- ExtJs 实现动态列,动态多表头