Stirling公式:n! ~ sqrt(2*π*n)(n/e)n
生成算法1:Johnson,Trotter
要生成全排列n,则在全排列n-1上,每个排列用插空法插入n
n=2:
1 2
2 1
n=3:
1 2 3
1 3 2
3 1 2
3 2 1
2 3 1
2 1 3
生成算法2:S.Even, Algorithm Combinatorics, 1973
如果一个数k的箭头指向一个比他小的相邻的数,那么称k是活动的
对于1..n的序列中的整数n,除以下两种情况外,n总是活动的
1. n在最左边,n的箭头指向左
2. n在最右边,n的箭头指向右
生成方法:从123..n开始(每个肩头初始指向左),做:
1. 求出最大的活动整数m
2. 交换m和其指向的整数
3. 交换所有p>m的整数p的方向
直到序列中没有活动整数为止。
#include <iostream> #define F(i,a,b) for (int i=a;i<=b;i++) using namespace std; int a[10001], move[10001], n; int hasActive() { int pos = 0, _max = 0; F(i,1,n) if (i+move[i]>0 && i+move[i]<=n && a[i]>a[ i+move[i] ] && a[i]>_max) pos = i, _max = a[i]; return pos; } int main() { freopen("out.txt", "w", stdout); int m; scanf("%d", &n); F(i,1,n) a[i] = i, move[i] = -1; F(i,1,n) printf("%d ", a[i]); printf("/n"); while ( m = hasActive() ) { swap( a[m], a[ m+move[m] ]); int mm = m+move[m]; swap( move[m], move[ m+move[m] ]); m = mm; F(i,1,n) printf("%d ", a[i]); printf("/n"); F(i, 1, n) if (a[i]>a[m]) move[i]*=-1; } return 0; }
生成所有组合方案:
基2算法:
从an-1..a2a1a0=00..0开始,当an-1..a2a1a0!=11..1,做
1. 求出最小的j使得aj=0
2. 用1替换aj并用0替换所有aj-1aj-2..a0
生成的序称为n元组的字典序
Gray码生成:
算法1:
1. 1阶Gray码是0, 1
2. 假设n-1阶Gray码已经生成,首先给n-1阶Gray码前面加0,再给逆序n-1阶Gray码前面加1。
算法2:
从an-1..a2a1a0=00..0开始,当an-1..a2a1a0!=10..0,做
1. 如果σ(an-1..a1a0)为偶数,则改变a0
2. 否则,找最小的j使得aj=1,改变aj+1
生成r-组合:
令 a1a2..ar是1..n的一个组合。字典序中,第一个组合是12..r。当a1a2..ar不是(n-r+1)(n-r+2)..n,令k是满足ak+1<=n且ak+1不是a1, a2..ar的最大整数,使用序列a1a2..ak-1(ak+1)(ak+2)..(ak+r-k+1)
例如:n=6的4组合中,1234的下一个组合是1235,2356的下一个组合是2456