先介绍生成排列的方法
最简单的方法是用STL自带的next_permutation() 参数为要生成下一个排列的区间
int n, p[10]; cin >> n; for (int i = 0; i < n; i++) cin >> p[i]; sort(p, p + n); do { for (int i = 0; i < n; i++) cout << p[i]; cout << endl; } while (next_permutation(p, p + n)); //若已经是最后一个排列则返回false这个函数还可以接受比较函数,默认是小于号
利用字典序方法(其实上面这个函数就是用这个方法生成下一个排列的)
先说下方法吧,以排列P1,P2,P3...Pn为例
1 先从又右向左找到第一个满足Pi-1<Pi的i
2 再从右向左找第一个比Pi-1大的数,假设是Pk
3 交换Pi-1与Pk,重新排列pi-1之后的数(不包含Pi-1)
int n, p[10]; cin >> n; for (int i = 0; i < n; i++) cin >> p[i]; sort(p, p + n); while (1) { for (int i = 0; i < n; i++) cout << p[i]; cout << endl; int i = n - 1; while (i > 0 && p[i - 1] > p[i]) i--; if (i == 0) break; //i==0说明已经是最后一个排列 int j; for (j = n - 1; j >= i; j--) if (p[j] > p[i - 1]) break; swap(p[i - 1], p[j]); sort(p + i, p + n); }
生成排列数这两种方法就足够了,建议使用第一种,简单好用
对于如何生成集合S={1,2...n)的r组合,直接参考博客代码
节省时间,并没有讲述原理,想了解的可以百度
1
void print_subset(int n, int *A, int cur) { //增量构造法 for (int i = 0; i < cur; i++) cout << A[i] + 1; //输出 puts(""); int s = cur ? A[cur - 1] + 1 : 0; //确定当前元素最小可能值 for (int i = s; i < n; i++) { A[cur] = i; print_subset(n, A, cur + 1); //递归构造子集 } } int main() { int n, a[10]; cin >> n; //n是集合元素的个数 print_subset(n, a, 0); system("pause"); }
2
void print_subset(int n, int *A, int cur) { //位向量法 if (cur == n) { for (int i = 0; i < cur; i++) if (A[i]) printf("%d", i + 1); puts(""); return; } A[cur] = 1; print_subset(n, A, cur + 1); A[cur] = 0; print_subset(n, A, cur + 1); } int main() { int n, a[10]; cin >> n; //n是集合元素的个数 print_subset(n, a, 0); system("pause"); }
3 (最简练)
void print_subset(int n, int s) { //二进制法 for (int i = 0; i < n; i++) if (s&(1 << i)) printf("%d", i + 1); printf("\n"); } int main() { int n, a[10]; cin >> n; //n是集合元素的个数 for (int i = 1; i < (1 << n); i++) print_subset(n, i); system("pause"); }