排列组合的算法 (algorithms for calculating permuration and combination)
排列组合的算法
定义字典序:
如果两个单词长度不同,较短的单词的每一个字符都和较长的单词相应的字符相同,那么短单词排在长单词的前面。
如果两个单词有相同或不同的长度,某个位置对应的字符不同,则单词的排序由左起第一个不同的字符来决定。
Lexicographic order
Let a=s1s2…sp and b=t1t2…tq be strings over {1,2,…n}. We say that a is lexicographically less than b and write a<b if either
(a) p<q and si=ti for I=1,…,p,
or
(b) for some I, si<>ti, and for the smallest such I, we have si<ti.
这里排列组合的算法都是基于字典序的,按字典序从小到大的顺序列出所有排列或组合,根据字典序发现规律,推导出算法。
求组合C(r,n)的算法,n是元素个数,r是选取的元素个数。
Given a string a=s1…sr, which represents r-combination {s1,…,sr}, to find the next string b=t1…tr, we find the rightmost element sm that is not at its maximum value.(sr may have the maximum value n, Sr-1 may have the maximum value n-1, etc). Then
Ti=si, for I=1, … , m-1.
The element tm is equal to sm+1. For the remainder of the string b we have Tm+1=sm+2, tm+2=sm+3, etc.
如下面的C(4,6)例子:
1 2 3 4
1 2 3 5
1 2 3 6
1 2 4 5
1 2 4 6
1 2 5 6
1 3 4 5
1 3 4 6
1 3 5 6
1 4 5 6
2 3 4 5
2 3 4 6
2 3 5 6
2 4 5 6
3 4 5 6
求组合P(n,n)的算法,P(r,n)的算法可以由C(r,n)和P(r,r)得到。
已知单词a=s1…sn, 为了得到下一个单词b=t1…tn,从右至左找到一个位置d,它右面的数r>d。然后把d后面的数中最小的大于d的数(从右向左搜索)和d交换,再把d所在位置后面的序列调整为由小到大的顺序。
如下面P(4,4)的例子:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1
3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2
3 4 2 1
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
附求排列和组合的代码:
using System;
public class CombinationPermutation
{
public static void Main()
{
Console.WriteLine("combination");
C(6,4);
Console.WriteLine("permutation");
P(4);
}
public static void PrintSeq(int[] s)
{
for(int i=0;i<s.Length;i++)
Console.Write("{0,2}",s[i]);
Console.WriteLine();
}
public static int Fac(int n)
{
int nRet=1;
for(int i=2;i<=n;i++)
nRet*=i;
return nRet;
}
public static int CountC(int n, int r)
{
return Fac(n)/Fac(n-r)/Fac(r);
}
private static int[] seq={1,2,3,4,5,6};
//algorithm of Permutation
public static void P(int n)
{
int[] a=new int[n];
for(int i=0;i<n;i++) a[i]=seq[i];
PrintSeq(a);
int nCount=Fac(n);
for( int k=1;k<nCount;k++)
{
int m=n-2;
while (a[m]>a[m+1]) m--;
int q=n-1;
while(a[q]<a[m]) q--;
int tmp;
tmp=a[m];
a[m]=a[q];
a[q]=tmp;
m=m+1;
q=n-1;
while (m<q)
{
tmp=a[m];
a[m]=a[q];
a[q]=tmp;
q--;
m++;
}
PrintSeq(a);
}
}
//algorithm of Combination
public static void C(int n, int r)
{
int[] a=new int[r];
for(int i=0;i<r;i++)
a[i]=seq[i];
PrintSeq(a);
for( int k=1;k<CountC(n,r);k++)
{
int max_val=seq[n-1];
int m=r-1;
while(a[m]==max_val)
{
m-=1;
max_val-=1;
}
a[m]+=1;
for(int j=m+1;j<r;j++)
a[j]=a[j-1]+1;
PrintSeq(a);
}
}
}
浙公网安备 33010602011771号