2 、 组合

2.1 组合公式

1. C(m,n)=C(m,m-n)
2. C(m,n)=C(m-1,n)+C(m-1,n-1)
derangement D(n) = n!(1 - 1/1! + 1/2! - 1/3! + ... + (-1)^n/n!)
= (n-1)(D(n-2) - D(n-1))
Q(n) = D(n) + D(n-1)
求和公式,k = 1..n
1. sum( k ) = n(n+1)/2
2. sum( 2k-1 ) = n^2
3. sum( k^2 ) = n(n+1)(2n+1)/6
4. sum( (2k-1)^2 ) = n(4n^2-1)/3
5. sum( k^3 ) = (n(n+1)/2)^2
6. sum( (2k-1)^3 ) = n^2(2n^2-1)
7. sum( k^4 ) = n(n+1)(2n+1)(3n^2+3n-1)/30
8. sum( k^5 ) = n^2(n+1)^2(2n^2+2n-1)/12
9. sum( k(k+1) ) = n(n+1)(n+2)/3
10. sum( k(k+1)(k+2) ) = n(n+1)(n+2)(n+3)/4
12. sum( k(k+1)(k+2)(k+3) ) = n(n+1)(n+2)(n+3)(n+4)/5

2.2 排列组合生成

//gen_perm产生字典序排列 P(n,m)
//gen_comb 产生字典序组合 C(n,m)
//gen_perm_swap 产生相邻位对换全排列 P(n,n)
//产生元素用 1..n 表示
//dummy 为产生后调用的函数,传入 a[]和 n,a[0]..a[n-1]为一次产生的结果
#define MAXN 100
int count;
#include <iostream.h>
void dummy(int* a,int n){
int i;
cout<<count++<<": ";
for (i=0;i<n-1;i++)
cout<<a[i]<<' ';
cout<<a[n-1]<<endl;
}
void _gen_perm(int* a,int n,int m,int l,int* temp,int* tag){
int i;
if (l==m)
dummy(temp,m);
else
for (i=0;i<n;i++)
if (!tag[i]){
temp[l]=a[i],tag[i]=1;
_gen_perm(a,n,m,l+1,temp,tag);
tag[i]=0;
}
}
void gen_perm(int n,int m){
int a[MAXN],temp[MAXN],tag[MAXN]={0},i;
for (i=0;i<n;i++)
a[i]=i+1;
_gen_perm(a,n,m,0,temp,tag);
}
void _gen_comb(int* a,int s,int e,int m,int& count,int* temp){
int i;
if (!m)
dummy(temp,count);
else
for (i=s;i<=e-m+1;i++){
temp[count++]=a[i];
_gen_comb(a,i+1,e,m-1,count,temp);
count--;
}
}
void gen_comb(int n,int m){
int a[MAXN],temp[MAXN],count=0,i;
for (i=0;i<n;i++)
a[i]=i+1;
_gen_comb(a,0,n-1,m,count,temp);
}
void _gen_perm_swap(int* a,int n,int l,int* pos,int* dir){
int i,p1,p2,t;
if (l==n)
dummy(a,n);
else{
_gen_perm_swap(a,n,l+1,pos,dir);
for (i=0;i<l;i++){
p2=(p1=pos[l])+dir[l];
t=a[p1],a[p1]=a[p2],a[p2]=t;
pos[a[p1]-1]=p1,pos[a[p2]-1]=p2;
_gen_perm_swap(a,n,l+1,pos,dir);
}
dir[l]=-dir[l];
}
}
void gen_perm_swap(int n){
int a[MAXN],pos[MAXN],dir[MAXN],i;
for (i=0;i<n;i++)
a[i]=i+1,pos[i]=i,dir[i]=-1;
_gen_perm_swap(a,n,0,pos,dir);
}

2.3 生成 gray 码

//生成 reflected gray code
//每次调用 gray 取得下一个码
//000...000 是第一个码,100...000 是最后一个码
void gray(int n,int *code){
int t=0,i;
for (i=0;i<n;t+=code[i++]);
if (t&1)
for (n--;!code[n];n--);
code[n-1]=1-code[n-1];
}

2.4 置换(polya)

//求置换的循环节,polya 原理
//perm[0..n-1]为 0..n-1 的一个置换(排列)
//返回置换最小周期,num 返回循环节个数
#define MAXN 1000
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int polya(int* perm,int n,int& num){
int i,j,p,v[MAXN]={0},ret=1;
for (num=i=0;i<n;i++)
if (!v[i]){
for (num++,j=0,p=i;!v[p=perm[p]];j++)
v[p]=1;
ret*=j/gcd(ret,j);
}
return ret;
}

2.5 字典序全排列

//字典序全排列与序号的转换
int perm2num(int n,int *p){
int i,j,ret=0,k=1;
for (i=n-2;i>=0;k*=n-(i--))
for (j=i+1;j<n;j++)
if (p[j]<p[i])
ret+=k;
return ret;
}
void num2perm(int n,int *p,int t){
int i,j;
for (i=n-1;i>=0;i--)
p[i]=t%(n-i),t/=n-i;
for (i=n-1;i;i--)
for (j=i-1;j>=0;j--)
if (p[j]<=p[i])
p[i]++;
}

2.6 字典序组合

//字典序组合与序号的转换
//comb 为组合数 C(n,m),必要时换成大数,注意处理 C(n,m)=0|n<m
int comb(int n,int m){
int ret=1,i;
m=m<(n-m)?m:(n-m);
for (i=n-m+1;i<=n;ret*=(i++));
for (i=1;i<=m;ret/=(i++));
return m<0?0:ret;
58
}
int comb2num(int n,int m,int *c){
int ret=comb(n,m),i;
for (i=0;i<m;i++)
ret-=comb(n-c[i],m-i);
return ret;
}
void num2comb(int n,int m,int* c,int t){
int i,j=1,k;
for (i=0;i<m;c[i++]=j++)
for (;t>(k=comb(n-j,m-i-1));t-=k,j++);
}

猜你喜欢

转载自www.cnblogs.com/godoforange/p/11240456.html
今日推荐