7.2 枚举排列
有没有想过如何打印所有排列呢?输入整数n,按字典序从小到大的顺序输出前n个数的所有排列。两个序列的字典序大小关系等价于从头开始第一个不相同位置处的大小关系
eg:(1,3,2)<(2,1,3),字典序最小的排列是(1,2,3,4,...,n),最大的排列是(n,n-1,n-2,...,1)
7.2.1 生成1~n的排列
点击查看笔者代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, v[100], ans[100];
void dfs(int p, int val[100]) {
if(p==n) {
for(int i = 0; i < n; i++) cout << ans[i] << " ";
cout << endl;
return;
}
for(int i = 0; i < n; i++) {
if(val[i]) {
ans[p] = val[i];
val[i] = 0;
dfs(p+1, val);
val[i] = i+1;
}
}
}
int main() {
cin >> n;
for(int i = 0; i < n; i++) v[i] = i+1;
dfs(0, v);
return 0;
}
下面考虑程序实现,很明显序列A可以用数组表示,注意这边作者的构思最巧妙的地方在于S根本没必要出现,因为用一个参数记录当前所在位置,那么数组A后面的元素都是待排列的
代码实现如下
点击查看代码
void print_permutation(int n, int* A, int cur) {
if(cur == n) {
for(int i = 0; i < n; i++) printf("%d ", A[i]);
printf("\n");
}
else for(int i = 1; i <= n; i++) { //尝试在A[cur]中填各种整数
int ok = 1;
for(int 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); //递归调用
}
}
}
循环变量i是当前考察的A[cur]。这边通过标志变量ok来实现对于i是否用过的检测
7.2.2 生成可重集的排列
因为之前的代码作者是认为每个元素都不相同来进行全排列的,此时里面的元素出现了重数,所以我们也要对应的多出一维的描述量来记录i元素出现的次数,和原先集合中i元素出现的次数,只要没有超出,就可以继续递归调用,但是这样子同样是会存在问题的,因为这样子相同的元素此时是当作不同的元素来看待的,但是理论上1(1)1(2)1(3)和1(2)1(1)1(3)这两个组合应该是一样的,但是不同的1出现的次数此时认为是不同的,那么解决办法就是因为所需要排列的组合在之前就进行过排序,那么从第一元素之后,只要和前面的元素相同那么cur这个地方就不能再填入该元素了,也就是变相的实现了,相同元素只能填入一次,同时也非常符合全排列的实现,也就是对于cur这个位置,是当前可以填入的元素的集合,各有且只有一个元素类似于set
点击查看代码
#include<iostream>
using namespace std;
void print_permutation(int n, int* P, int* A, int cur) {
if(cur ==n) {
for(int i = 0; i < n; i++) printf("%d ", A[i]);
printf("\n");
}
else for(int i = 0; i < n; i++) {
if(i && P[i] == P[i-1]) continue;//这边主要是排序过的因此,重复的元素是集合成一起的,所以可以使用,同时利用短路机制实现的
int c1 = 0, c2 = 0;
for(int j = 0; j < cur; j++) if(A[j] == P[i]) c1++;
for(int 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);
}
}
/*
else for(int i = 1; i <= n; i++) {
int ok = 1;
for(int j = 0; j < cur; j++)
if(A[j] == i) ok = 0;
if(ok) {
A[cur] = i;
printf_permuataion(n, A, cur+1);
}
}
*/
}
int main() {
int n1[10], n2[10];
for(int i = 0; i < 10; i++) {
n1[i] = 1;
n2[i] = i+1;
}
print_permutation(3, n1, n2, 0);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)