生成排列组合(Brualdi第4章)笔记

生成排列

Stirling公式:n! ~ sqrt(2*π*n)(n/e)n

生成算法1Johnson,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

你可能感兴趣的:(生成排列组合(Brualdi第4章)笔记)