1.生成1~n的排列
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//使用普通数组实现
void print_permutation(int n, int *A, int cur, int &cnt){ //由于无法知道数组的元素个数,用cur进行保存
if(cur == n){
cnt++;
for(int i = 0; i < n; i++)printf("%d", A[i]);
printf("\n");
}else{
for(int i = 1; i <= n; i++){
bool flag = true;
for(int j = 0; j < cur; j++){
if(A[j] == i){flag = false; break;} //不能选择里面已经有的数字
}
if(flag){
A[cur] = i;
print_permutation(n, A, cur+1, cnt); //递归调用
}
}
}
}
//使用vector容器实现
void print_permutation2(int n, vector<int>A, int &cnt){
if((int)A.size() == n){
cnt++;
for(int i = 0; i < n; i++)printf("%d", A[i]);
printf("\n");
}else{
for(int i = 1; i <= n; i++){
vector<int>::iterator iter=find(A.begin(),A.end(),i);
if(iter == A.end()){
A.push_back(i);
print_permutation2(n, A, cnt);
A.erase(A.end() - 1);
}
}
}
}
int main(){
int n = 6, A[10], cnt = 0;
vector<int>B;
printf("使用普通数组实现\n\n\n");
print_permutation(n, A, 0, cnt);
printf("\n");
printf("使用vector实现\n\n");
cnt = 0;
print_permutation2(n, B, cnt);
printf("共计%d个\n", cnt);
}
- 生成可以重复的的排列
void print_permutationR(int n, int *A, int cur, int &cnt, int *P){
if(cur == n){
cnt++;
for(int i = 0; i < n; i++)printf("%d", A[i]);
printf("\n");
}else{
for(int i = 0; i < n; i++){
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]) if(!i || P[i] != P[i-1]) c2++;//不重复不遗漏取遍P的值
if(c1 < c2){
A[cur] = P[i];
print_permutationR(n, A, cur+1, cnt, P);
}
}
}
}
3.子集生成
方法一:增量构造法
void print_subset3(int n, int *A, int cur, int num[]){
printf("[ ");
for(int i = 0; i < cur; i++){
printf("%d ", num[A[i]]);
}
printf("]\n");
int s = cur ? A[cur-1]+1 : 0;
for(int i = s; i < n; i++){
A[cur] = i;
print_subset3(n, A, cur+1, num);
}
}
int main(){
int n = 3, A[10], P[3] = {1, 2, 3};
vector<int>B;
printf("使用增量构造法:\n");
print_subset3(n, A, 0, P);
}
方法二:使用位向量法
void print_subset2(int n, int *B, int cur, int num[]){
if(cur == n){
printf("[ ");
for(int i = 0; i < cur; i++){
if(B[i])printf("%d ", num[i]);
}
printf("]\n");
return ;
}
B[cur] = 1; //选择cur;
print_subset2(n, B, cur+1, num);
B[cur] = 0; //不选cur;
print_subset2(n, B, cur+1, num);
}
int main(){
int n = 3, A[10], P[3] = {1, 2, 3};
printf("使用位向量法:\n");
print_subset2(n, A, 0, P);
}
方法三,使用二进制方法
1.描述子集:使用二进制的一位表示子集的某个元素是否存在。
这样全集就可以使用(1<<n) - 1来表示,子集就是[0, 1<<n - 1]的一个数。
2.输出集合:使用了二进制的与,如果(s & (1<<i))表示子集的第i位存在,则输出。
void print_subset(int n, int s, int num[]){
printf("[ ");
for(int i = 0; i < n; i++){
if(s&(1<<i))printf("%d ", num[i]);
}
printf("]\n");
}
void get_subset(int n, int num[]){
for(int i = 0; i < (1<<n); i++){
print_subset(n, i, num);
}
}
int main(){
int P[3] = {1, 1, 3};
printf("子集为:\n");
get_subset(3, P);
}
1.回溯实例