全排列就是将n数字按照不同的顺序排列出来,比如给定3个数字,1 2 3,那这三个数字全排列就是
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
排列方法就是先定1个位置的数字,再定下一个,再定下一个就行,比如 1 2 3三个数:
A:先定数字1
1 ﹉ ﹉,那么第二个位置数字只能是2或者3,接下来先定2或3都行
1 2 ﹉那么最后一个数字就只能是3。
B:再回溯
上个例子,定了1 2 3,回溯第二步就是只选择了1
1 ﹉ ﹉,并且2已经选择过了,所以只能选择3,那么就是 1 3 ﹉,第三个数就只能是2,序列就是1 3 2。以此类推就行。
C代码部分:
因此我们需要一个数组来记录该数字是否访问。
就拿四个数字
1 2 3 4 ,递归的大体框架
﹉﹉﹉﹉﹉
void dfs(int step){
if(到达目的地){
输出解
}
返回
合理的剪枝操作:
for(int i = 1; i <=枚举数;i++){
if(满足条件){
更新状态位;
dfs(step+1);
恢复状态位;
}
}
}
﹉﹉﹉﹉
具体代码:
﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉
int k;k是数字个数
int i;
int a[10];//存储数字的数组
int used[10];//访问记录数组
void dfs(int step){ //step就是排列的数字
if(step==k){
for(i=0;i <k;i++){
printf("%d ", a[i]); //输出
}
printf("\n");
return;
}
for(i=0;i <k;i++){
if (used [i]==0){
used[i]= 1;
a[step] = i;
dfs (step+1);//递归
used[i] = 0; // 回溯
}
}
}
﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉
这就可以完成全排列,
同时也可以从5个数字排列4个数字使用俩个dfs函数即可,
同时添加一个数组用来记录5个数字选了哪4个数字全排列
然后用这个函数全排列4个。
同时选的四个也需要一个数组来记录是否用过,避免重复。
可以看一下
#include <stdio.h>
#define N 5 // 总共的数字个数
#define K 4 // 选出的数字个数
int nums[N] = {1, 2, 3, 4, 5}; // 初始数据
int selected[K]; // 存储选出的 4 个数字
int used[N] = {0}; // 记录哪些数被使用
int perm[K]; // 存储排列
int used_perm[K] = {0}; // 记录排列中哪些数已使用
// 递归生成排列
int k=0;
void permute(int depth) {
if (depth == K) { // 当排列长度达到 K
for (int i = 0; i < K; i++) {
printf("%d ", perm[i]);
}
k++;
printf("\n");
return;
}
for (int i = 0; i < K; i++) {
if (!used_perm[i]) { // 确保元素不重复使用
used_perm[i] = 1;
perm[depth] = selected[i];
permute(depth + 1);
used_perm[i] = 0; // 回溯
}
}
}
// 递归生成组合
void combine(int start, int depth) {
if (depth == K) { // 选满 4 个数后,进行全排列
for (int i = 0; i < K; i++) {
used_perm[i] = 0; // 初始化排列使用标记
}
permute(0); // 对当前选出的 4 个数进行全排列
return;
}
for (int i = start; i < N; i++) {
if (!used[i]) {
used[i] = 1;
selected[depth] = nums[i];
combine(i + 1, depth + 1);
used[i] = 0; // 回溯
}
}
}
int main() {
combine(0, 0); // 生成所有 4 个数的组合,并对每个组合求全排列
printf("%d",k);
return 0;
}