270 likes | 345 Views
§3-1 排列问题. n 个元素共有 n! 个排列。 不重复无遗漏地产生 n 个元素的所有 n! 个排列。 思路: 设连续产生的两个排列为 P 和 P', 只要将 P 中的两个元素交换位置就得排列 P' .. 定义 将一个排列的两个元素交换位置的操作称为换位,记作 t. 所有可能的换位操作的集合记为 T. 从而 n! 个排列可以这样来产生, 任意选择一个排列,然后连续使用 T 中的操作,得到其余的 (n! 一 1) 个排列。 这个方法实质上将 n! 个排列排成一个序列, 对其中每一个排列 ( 不是最后一个 ) 作一次换位操作,就可得其后继排列。.
E N D
n个元素共有n! 个排列。 不重复无遗漏地产生n个元素的所有n!个排列。 思路: 设连续产生的两个排列为P和P',只要将P中的两个元素交换位置就得排列P'.
定义 将一个排列的两个元素交换位置的操作称为换位,记作t. • 所有可能的换位操作的集合记为T.
从而n!个排列可以这样来产生, • 任意选择一个排列,然后连续使用T中的操作,得到其余的(n!一1)个排列。 • 这个方法实质上将n!个排列排成一个序列, • 对其中每一个排列(不是最后一个)作一次换位操作,就可得其后继排列。
以n=3为例,其六个排列的序列下: l 2 3 2 l 3 2 3 1 3 2 l 3 l 2 1 3 2
有n个元素的排列称为n排列。 • 从群论的角度问题可叙述如下,考虑有限群G及其算子集合T(现在G的元素是排列,T的元素是换位), • 能否将G的所有元素排成一个序列,每两个相邻的元素有这样的性质, • 前者使用t∈T一次,即可得后者。 • 下面用归纳法证对于排列而言,这样的序列存在。
对元素的个数n进行归纳。设n个元素为a1,a2,…,an.对元素的个数n进行归纳。设n个元素为a1,a2,…,an. • 当n=2时显然成立,共有两个排列, • 将其中的一个排列的仅有的两个元素交换位置即得另一个排列。 • 设n<p时存在n!个排列的序列,具有上述性质。
当n=p时,有p!个排列,用下述方法将它们组织成一个序列。考虑p个元素的前p-1个元素,因为p-1<p当n=p时,有p!个排列,用下述方法将它们组织成一个序列。考虑p个元素的前p-1个元素,因为p-1<p • 满足归纳假设的条件,可以得到(p-1)!个(p-1)排列, • 将最后一个元素ap加到它们末尾,即得(p一1)!个p排列,且具有上述性质, • 然后交换上述最后一个排列中元素ap和元素a1(现在al并不一定在第一个位置)的位置,
考虑这个排列的前(p-1)个元素,满足归纳假设的条件,可得(p-1)!个p排列(它们最末尾的元素为a1);考虑这个排列的前(p-1)个元素,满足归纳假设的条件,可得(p-1)!个p排列(它们最末尾的元素为a1); • 然后交换元素a1和元素a2,又可得 • (p-1)!个p排列,其末尾元素为a2; • 交换元素a2和元素a3,得(p一1)!个p排列,…, • 直至元素ap-2与元素ap-1交换位置, • 再得(p-1)!个p排列,其末尾元素为ap-1.
从而p个元素的每一个都出现在 • (p-1)!个p排列的末尾, • 因此共有p× (p-1)!=p!个p排列, • 且它们都是互不相同的, • 每两个相邻的p排列有这样的性质: • 前者使用一次换位操作就得到了后者。证毕。
从而,产生n!个n排列的问题变成给定一个n排列,如何确定要交换位置的两个元素。从而,产生n!个n排列的问题变成给定一个n排列,如何确定要交换位置的两个元素。 • 令序列中第m个排列为 • a1,a2,a3,⋯,an • 需要交换位置的两个元素为 • ar 和ah (r<h),ah在ar的右边,
这告诉我们a1,a2,…,ah-1 • 的(h-1)!个排列已经产生完毕, • 因此才需将其中的一个元素ar与它们右边的元素ah交换位置, • 从而m必是(h-1)!的倍数。 • m必不是h!的倍数。 • 换言之,h是具有下述性质的最小整数j: • m不能被j!整除。
h的值确定以后,r就很容易确定了。 • 上面的证明指明了确定r的方法。分两种情况: • (1)如a1,a2,…,ah-l都比ah小,则选择al,a2,…,ah-1中最小的元素与ah换位, • 不然则 • (2)选择a1,a2,…,ah-1中比ah大的元素中最小者与ah换位。
[例1] n为5.产生的第102个排列为 • 2 1 5 3 4 • 求第103个排列。 • m=102,因为 102÷3!=17余0 • 102÷4! = 3余30 • 所以,h=4,即元素3要与其左的一个元素交换位置,比3大的元素只有一个,为5, • 所以3和5交换位置,得第103个排列为 • 2 1 3 5 4
[例2] n=4,4!=24,使用上述方法产生的24个排列如下所示(自上而下,再向右): • 1234 432l 1342 1423 • 2134 342l 3142 4123 • 2314 2431 3412 2143 • 3214 423l 4312 1243 • 3124 324l 4132 4213 • 1324 234l 1432 2413
本节的主要结果是函数permu, • 它需要三个函数: • int FAC(int n) • //计算n的阶乘 • {int i =2, k=1; • for ( ;i<=n; ) k*=i++; • return k; • }
void SWAP(int x,int y,int a[ ]) • //交换数组a中下标为x及下标为y的元素的值 • {int t; • t=a[x]; • a[x] = a[y] ; • a[y] =t; • }
void PRlNT(int M, int n, int a[ ]) • {//打印n排列a及其序号M • int i=1; • printf (M); • for (;i<=n;) printf (a[i++]); • }
void PERMU (int n); • //产生n个元素1,2,…,N的n!个排列 • 产生第一和第二两个排列; • M=2; • while(M< fac (n)) • //每循环一次, 产生两个排列 • {确定h;确定r; • SWAP (r, h, a); PRINT(++ M, n, a); • SWAP (1, 2, a); PRINT(++ M, n, a); • }
产生第一和第二两个排列 • for( i=l ;i<=n; i++) a[i]=i; • PRINT(1,n,a); (2) • SWAP(1, 2, a); • PRINT(2,n,a); (3)
确定h; • h=2; (4) • do h2=FAC (++ h) ; (5) • while(M%h2==0) ; • 可修改为 • h=2; h2=2; (4) • do h2 *= ++ h ; (5) • while(M%h2==0) ;
确定r; • r=1; j=0; (6) • TEMP =MAXlNT; • for( i=l; i< h; i++) • {//寻找最小的值 • if(a[i] <a[r]) r=i • //寻找大于a[h]的最小值 • if((a[i] >a [h]) && (a [i] <TEMP)) • { j=i; • TEMP=a[i] • } • } • if(j ) r=j;
注1 当M为奇数时,h的值必为2,r的值则为1, 即需要交换第1个、第2个元素的位置, 因此过程PERMU中while语句的循环体每执行一次产生两个排列, 用前述方法确定h、r,交换a[h]、a [r]得到一个排列, 然后再交换a[1]、a[2]直接得到另一个排列。
注2 过程PERMU按前面的思路编写,为的是容易理解,为加速运行,将确定r的程序段更改为: • r=0;TEMP=MAXINT; • for( i=l; i< h; i++) • if((a[i] >a [h]) && ( a [i] <TEMP)) • {r=i; TEMP=a[i];} • if( r= =0) • { r=1; • for( i=2;i<n;i++) • if(a[i]<a[r]) r=i; • }
经这样更改,不仅省时间,还省去变量j和函数FAC经这样更改,不仅省时间,还省去变量j和函数FAC
注3 还有一种方法确定r的值,也分两种情况。 • ①如al,a2,…,ah-1都比ah大,则选择a1,a2,…,ah-1中最大者与a[h]交换,否则 • ②选择a1,a2,…,ah-1中比ah小的元素中最大者与a[h]交换。以n=4为例, • 用上述方法得到的24个排列为
1234 4213 4132 3241 • 2134 2413 1432 234l • 3124 2143 3412 243l • 1324 1243 4312 4231 • 2314 1423 1342 4321 • 3214 4123 3142 342l