aabbcc本质不同的排列数
Stainhaus在其名著《一百个数学问题》中给出了如下问题:
“由aabbcc这组字母可以得出90种不同的排列,其中有些如aabcbc、aacbcb、bcbcaa及acacbb之间 并无本质差别,因为c、b互换,则可由第一个排列得出第2个排列,若逆向看第2个排列,可以发现它与第三个排列等价;而在第3个排列中,若将a、b互换,则生成第4个排列,我们将这种无本质差别的排列看成是相同类型的排列,而排列aabcbc和abcabc这两个排列无论用字母替换法还是逆向阅读法,甚至交替使用,也不能将前一种排列变为后一种,所以我们将这样的排列称为不同类型的排列。试问:aabbcc这6个字母共能组成多少种本质不同的排列类型。”
~~~~~~~~~~~~~~
多重元素集合的排列生成法
多重元素集合是指集合中一个元素可以重复出现多次的集合。例如多重元素集合{1,2,2,3,3,3}中元素1出现1次,2出现2次,3出现3次,而多重元素集合{1,1,2,2,3,3}中元素1、2、3均出现2次。多重元素集合的排列是指所有集合元素所构成的一个排列,一个元素在集合中出现几次,它在排列中同样要出现几次,例如,多重元素集合{1,1,2,2}共有6个不同的排列,它们分别是:
1122
1212
1221
2112
2121
2211
若一个集合中含k1个a1,k2个a2,…,kn个an,则该多重集合的不同排列数为:
(k1+k2+…+kn)!/k1!k2!...kn!
下面我们考虑多重元素集合的排列枚举算法。
我们将元素为表的表称为二重表,多重元素的集合可以表示成二重表的形式。例如,多重元素集合{1,2,2,3,3,3}表示成二重表[[1],[2,2],[3,3,3]]的形式。
domains
ilist=integer*
ilists=ilist*
predicates
nondeterm dup_perm(ilists, ilist)
nondeterm dup_perm_3(ilists, ilist, ilist)
nondeterm merge(ilist, ilist, ilist)
clauses
dup_perm([], []).
dup_perm([L|Ls], P):-dup_perm_3(Ls, L, P).
dup_perm_3([], P, P).
dup_perm_3([L|Ls], P0, P):-
merge(L, P0, P1),
dup_perm_3(Ls, P1, P).
merge([], L, L):-!.
merge(L, [], L):-!.
merge([X|L1], L2, [X|L]):-merge(L1, L2, L).
merge(L1, [X|L2], [X|L]):-merge(L1, L2, L).
goal
dup_perm([[1,1],[2,2],[3,3]], P),
write(P), nl,
fail.
上述目标生成的全部解为:
[3,3,2,2,1,1]
[3,2,3,2,1,1]
[3,2,2,3,1,1]
[3,2,2,1,3,1]
[3,2,2,1,1,3]
[2,3,3,2,1,1]
[2,3,2,3,1,1]
[2,3,2,1,3,1]
[2,3,2,1,1,3]
[2,2,3,3,1,1]
[2,2,3,1,3,1]
[2,2,3,1,1,3]
[2,2,1,3,3,1]
[2,2,1,3,1,3]
[2,2,1,1,3,3]
[3,3,2,1,2,1]
[3,2,3,1,2,1]
[3,2,1,3,2,1]
[3,2,1,2,3,1]
[3,2,1,2,1,3]
[2,3,3,1,2,1]
[2,3,1,3,2,1]
[2,3,1,2,3,1]
[2,3,1,2,1,3]
[2,1,3,3,2,1]
[2,1,3,2,3,1]
[2,1,3,2,1,3]
[2,1,2,3,3,1]
[2,1,2,3,1,3]
[2,1,2,1,3,3]
[3,3,2,1,1,2]
[3,2,3,1,1,2]
[3,2,1,3,1,2]
[3,2,1,1,3,2]
[3,2,1,1,2,3]
[2,3,3,1,1,2]
[2,3,1,3,1,2]
[2,3,1,1,3,2]
[2,3,1,1,2,3]
[2,1,3,3,1,2]
[2,1,3,1,3,2]
[2,1,3,1,2,3]
[2,1,1,3,3,2]
[2,1,1,3,2,3]
[2,1,1,2,3,3]
[3,3,1,2,2,1]
[3,1,3,2,2,1]
[3,1,2,3,2,1]
[3,1,2,2,3,1]
[3,1,2,2,1,3]
[1,3,3,2,2,1]
[1,3,2,3,2,1]
[1,3,2,2,3,1]
[1,3,2,2,1,3]
[1,2,3,3,2,1]
[1,2,3,2,3,1]
[1,2,3,2,1,3]
[1,2,2,3,3,1]
[1,2,2,3,1,3]
[1,2,2,1,3,3]
[3,3,1,2,1,2]
[3,1,3,2,1,2]
[3,1,2,3,1,2]
[3,1,2,1,3,2]
[3,1,2,1,2,3]
[1,3,3,2,1,2]
[1,3,2,3,1,2]
[1,3,2,1,3,2]
[1,3,2,1,2,3]
[1,2,3,3,1,2]
[1,2,3,1,3,2]
[1,2,3,1,2,3]
[1,2,1,3,3,2]
[1,2,1,3,2,3]
[1,2,1,2,3,3]
[3,3,1,1,2,2]
[3,1,3,1,2,2]
[3,1,1,3,2,2]
[3,1,1,2,3,2]
[3,1,1,2,2,3]
[1,3,3,1,2,2]
[1,3,1,3,2,2]
[1,3,1,2,3,2]
[1,3,1,2,2,3]
[1,1,3,3,2,2]
[1,1,3,2,3,2]
[1,1,3,2,2,3]
[1,1,2,3,3,2]
[1,1,2,3,2,3]
[1,1,2,2,3,3]
问题总共有90个解,即6!/2!2!2!.
~~~~~~~~~~~~~~~~~~~~~~~~~~
如何产生112233所有本质不同的排列?
我们首先定义两个排列的字典序:
a(1)a(2)…a(n)<b(1)b(2)…b(n) iff 存在k,1≤k≤n,使得a(1)=b(1),a(2)=b(2),…,a(k-1)=b(k-1)且a(k)<b(k)
一个排列称为基本解,如果它经过群S3元素及排列逆序变换反复作用后,不会变换为字典序更小的排列。
由于两次逆序变换将一个排列变成自身,因此,我们可以按照下面的方法来判断一个排列是否基本解:
(1) 在群S3元素的作用下,该排列字典序是否会减小?如果减小,则该排列不是基本解。判断的方法是:在排列中,1、2、3的首次出现次序是1在最前面,2其次,3在最后;
(2) 对排列进行逆序变换,然后将其最小化。所谓最小化,是指对逆序变换的排列进行变换(变换取自S3),使得1、2、3的首次出现次序按从小到大的次序排列。如果最小化后的排列比原排列字典序小,则原排列不是基本解。
对于上述问题进行手工验算。首先,我们考虑判断原则(1),则基本解只需在下面15个解中寻找:
[1,2,3,3,2,1]
[1,2,3,2,3,1]
[1,2,3,2,1,3]
[1,2,2,3,3,1]
[1,2,2,3,1,3]
[1,2,2,1,3,3]
[1,2,3,3,1,2]
[1,2,3,1,3,2]
[1,2,3,1,2,3]
[1,2,1,3,3,2]
[1,2,1,3,2,3]
[1,2,1,2,3,3]
[1,1,2,3,3,2]
[1,1,2,3,2,3]
[1,1,2,2,3,3]
利用判断原则(2),我们找到问题的11个基本解。
|
逆序变换
|
最小化变换
|
最小化结果
|
是否基本解?
|
123321
|
123321
|
(1)(2)(3)
|
123321
|
基本解
|
123231
|
132321
|
(23)
|
123231
|
基本解
|
123213
|
312321
|
(123)
|
123132
|
|
122331
|
133221
|
(23)
|
122331
|
基本解
|
122313
|
313221
|
(123)
|
121332
|
|
122133
|
331221
|
(123)
|
112331
|
|
123312
|
213321
|
(12)
|
123312
|
基本解
|
123132
|
231321
|
(132)
|
123213
|
基本解
|
123123
|
321321
|
(13)
|
123123
|
基本解
|
121332
|
233121
|
(132)
|
122313
|
基本解
|
121323
|
323121
|
(13)
|
121323
|
基本解
|
121233
|
332121
|
(13)
|
112321
|
|
112332
|
233211
|
(132)
|
122133
|
基本解
|
112323
|
323211
|
(13)
|
121233
|
基本解
|
112233
|
332211
|
(13)
|
112233
|
基本解
|
基本解的判断程序如下:
domains
ilist=integer*
ilists=ilist*
tr=t(integer,integer)
trlist=tr*
predicates
nondeterm dup_perm(ilists, ilist)
nondeterm dup_perm_3(ilists, ilist, ilist)
nondeterm merge(ilist, ilist, ilist)
nondeterm aabbcc(ilist)
nondeterm is_primary_perm(ilist)
nondeterm check1(ilist)
nondeterm check2(ilist)
nondeterm reverse(ilist, ilist)
nondeterm reverse_3(ilist, ilist, ilist)
nondeterm le(ilist, ilist)
nondeterm s3(integer, trlist)
nondeterm trans(trlist, ilist, ilist)
nondeterm find_trans_member(tr, trlist)
clauses
aabbcc(P):-
dup_perm([[1,1],[2,2],[3,3]], P),
is_primary_perm(P).
is_primary_perm(P):-
check1(P),
check2(P).
check1(P):-
s3(1, T1), trans(T1, P, P1), le(P,P1),
s3(2, T2), trans(T2, P, P2), le(P,P2),
s3(3, T3), trans(T3, P, P3), le(P,P3),
s3(4, T4), trans(T4, P, P4), le(P,P4),
s3(5, T5), trans(T5, P, P5), le(P,P5),
s3(6, T6), trans(T6, P, P6), le(P,P6).
check2(P):-
reverse(P,R),
s3(1, T1), trans(T1, R, R1), le(P,R1),
s3(2, T2), trans(T2, R, R2), le(P,R2),
s3(3, T3), trans(T3, R, R3), le(P,R3),
s3(4, T4), trans(T4, R, R4), le(P,R4),
s3(5, T5), trans(T5, R, R5), le(P,R5),
s3(6, T6), trans(T6, R, R6), le(P,R6).
reverse(L, R):-reverse_3(L, [], R).
reverse_3([H|L], T, R):-
reverse_3(L, [H|T], R).
reverse_3([], R, R).
le([],[]).
le([X1|_], [X2|_]):-X1 < X2.
le([X|L1], [X|L2]):-le(L1, L2).
s3(1, [t(1,1), t(2,2), t(3,3)]).
s3(2, [t(1,1), t(2,3), t(3,2)]).
s3(3, [t(1,2), t(2,1), t(3,3)]).
s3(4, [t(1,2), t(2,3), t(3,1)]).
s3(5, [t(1,3), t(2,1), t(3,2)]).
s3(6, [t(1,3), t(2,2), t(3,1)]).
trans(_, [], []).
trans(T, [X|P1], [Y|P2]):-
find_trans_member(t(X,Y), T),
trans(T, P1, P2).
find_trans_member(t(X,Y), [t(X,Y)|_]):-!.
find_trans_member(t(X,Y), [t(Z,_)|T]):-
X <> Z,
find_trans_member(t(X,Y), T).
dup_perm([], []).
dup_perm([L|Ls], P):-dup_perm_3(Ls, L, P).
dup_perm_3([], P, P).
dup_perm_3([L|Ls], P0, P):-
merge(L, P0, P1),
dup_perm_3(Ls, P1, P).
merge([], L, L):-!.
merge(L, [], L):-!.
merge([X|L1], L2, [X|L]):-merge(L1, L2, L).
merge(L1, [X|L2], [X|L]):-merge(L1, L2, L).
goal
aabbcc(P),
write(P), nl,
fail.
上述目标生成的全部11个解,这与我们分析的结果是一致的:
[1,2,3,3,2,1]
[1,2,3,2,3,1]
[1,2,2,3,3,1]
[1,2,3,3,1,2]
[1,2,3,1,3,2]
[1,2,3,1,2,3]
[1,2,1,3,3,2]
[1,2,1,3,2,3]
[1,1,2,3,3,2]
[1,1,2,3,2,3]
[1,1,2,2,3,3]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
上述程序是有局限的,我们枚举了S3的所有元素,并采用一种特殊的数据结构来简化问题求解的逻辑。如何将上述程序进行修改,使之适应于任意多重元素集合本质不同的排列的枚举,可以进一步探讨。但是上述程序适应于3个元素任意多重排列的情况,例如,当每个元素均为3重时,我们要求111222333本质不同的排列,可以修改aabbcc谓词为:
aabbcc(P):-
dup_perm([[1,1,1],[2,2,2],[3,3,3]], P),
is_primary_perm(P).
程序运行生成全部148个解:
[1,2,2,2,1,3,3,3,1]
[1,2,3,2,1,3,3,2,1]
[1,2,3,2,1,3,2,3,1]
[1,2,2,3,3,1,3,2,1]
[1,2,2,3,3,1,2,3,1]
[1,2,2,3,3,1,2,1,3]
[1,2,2,3,1,3,3,2,1]
[1,2,2,3,1,3,2,3,1]
[1,2,2,3,1,3,2,1,3]
[1,2,2,3,1,2,3,3,1]
[1,2,2,1,3,3,3,2,1]
[1,2,2,1,3,3,2,3,1]
[1,2,2,1,3,3,2,1,3]
[1,2,2,1,3,2,3,3,1]
[1,2,2,1,2,3,3,3,1]
[1,2,3,3,2,1,1,2,3]
[1,2,3,2,3,1,3,1,2]
[1,2,3,2,3,1,1,3,2]
[1,2,3,2,3,1,1,2,3]
[1,2,3,2,1,3,3,1,2]
[1,2,3,2,1,3,1,3,2]
[1,2,2,3,3,3,1,1,2]
[1,2,2,3,3,1,3,1,2]
[1,2,2,3,3,1,1,3,2]
[1,2,2,3,3,1,1,2,3]
[1,2,2,3,1,3,3,1,2]
[1,2,2,3,1,3,1,3,2]
[1,2,2,3,1,3,1,2,3]
[1,2,2,3,1,1,3,3,2]
[1,2,2,1,3,3,3,1,2]
[1,2,2,1,3,3,1,3,2]
[1,2,2,1,3,3,1,2,3]
[1,2,2,1,3,1,3,3,2]
[1,2,2,1,1,3,3,3,2]
[1,2,3,3,1,2,2,3,1]
[1,2,3,3,1,2,2,1,3]
[1,2,3,1,3,2,3,2,1]
[1,2,3,1,3,2,2,3,1]
[1,2,3,1,3,2,2,1,3]
[1,2,3,1,2,3,3,2,1]
[1,2,3,1,2,3,2,3,1]
[1,2,3,1,2,3,2,1,3]
[1,2,1,3,3,3,2,2,1]
[1,2,1,3,3,2,3,2,1]
[1,2,1,3,3,2,2,3,1]
[1,2,1,3,3,2,2,1,3]
[1,2,1,3,2,3,3,2,1]
[1,2,1,3,2,3,2,3,1]
[1,2,1,3,2,3,2,1,3]
[1,2,1,3,2,2,3,3,1]
[1,2,1,3,2,2,3,1,3]
[1,2,1,2,3,3,3,2,1]
[1,2,1,2,3,3,2,3,1]
[1,2,1,2,3,3,2,1,3]
[1,2,1,2,3,2,3,3,1]
[1,2,1,2,3,2,3,1,3]
[1,2,1,2,2,3,3,3,1]
[1,2,3,1,3,2,3,1,2]
[1,2,3,1,3,2,1,2,3]
[1,2,3,1,2,3,3,1,2]
[1,2,3,1,2,3,1,3,2]
[1,2,3,1,2,3,1,2,3]
[1,2,1,3,3,3,2,1,2]
[1,2,1,3,3,2,3,1,2]
[1,2,1,3,3,2,1,3,2]
[1,2,1,3,3,2,1,2,3]
[1,2,1,3,2,3,3,1,2]
[1,2,1,3,2,3,1,3,2]
[1,2,1,3,2,3,1,2,3]
[1,2,1,3,2,1,3,3,2]
[1,2,1,3,2,1,3,2,3]
[1,2,1,2,3,3,3,1,2]
[1,2,1,2,3,3,1,3,2]
[1,2,1,2,3,3,1,2,3]
[1,2,1,2,3,1,3,3,2]
[1,2,1,2,3,1,3,2,3]
[1,2,1,2,1,3,3,3,2]
[1,2,1,3,3,1,2,2,3]
[1,2,1,3,1,3,2,2,3]
[1,2,1,3,1,2,3,3,2]
[1,2,1,1,3,3,2,3,2]
[1,2,1,1,3,3,2,2,3]
[1,2,1,1,3,2,3,3,2]
[1,2,1,1,3,2,3,2,3]
[1,2,1,1,2,3,3,3,2]
[1,2,1,1,2,3,3,2,3]
[1,1,2,3,3,3,2,2,1]
[1,1,2,3,3,2,3,2,1]
[1,1,2,3,3,2,2,3,1]
[1,1,2,3,3,2,2,1,3]
[1,1,2,3,2,3,3,2,1]
[1,1,2,3,2,3,2,3,1]
[1,1,2,3,2,3,2,1,3]
[1,1,2,3,2,2,3,3,1]
[1,1,2,3,2,2,3,1,3]
[1,1,2,3,2,2,1,3,3]
[1,1,2,2,3,3,3,2,1]
[1,1,2,2,3,3,2,3,1]
[1,1,2,2,3,3,2,1,3]
[1,1,2,2,3,2,3,3,1]
[1,1,2,2,3,2,3,1,3]
[1,1,2,2,3,2,1,3,3]
[1,1,2,2,2,3,3,3,1]
[1,1,2,2,2,3,3,1,3]
[1,1,2,3,3,3,2,1,2]
[1,1,2,3,3,2,3,1,2]
[1,1,2,3,3,2,1,3,2]
[1,1,2,3,3,2,1,2,3]
[1,1,2,3,2,3,3,1,2]
[1,1,2,3,2,3,1,3,2]
[1,1,2,3,2,3,1,2,3]
[1,1,2,3,2,1,3,3,2]
[1,1,2,3,2,1,3,2,3]
[1,1,2,3,2,1,2,3,3]
[1,1,2,2,3,3,3,1,2]
[1,1,2,2,3,3,1,3,2]
[1,1,2,2,3,3,1,2,3]
[1,1,2,2,3,1,3,3,2]
[1,1,2,2,3,1,3,2,3]
[1,1,2,2,3,1,2,3,3]
[1,1,2,2,1,3,3,3,2]
[1,1,2,2,1,3,3,2,3]
[1,1,2,3,3,3,1,2,2]
[1,1,2,3,3,1,2,3,2]
[1,1,2,3,3,1,2,2,3]
[1,1,2,3,1,3,2,3,2]
[1,1,2,3,1,3,2,2,3]
[1,1,2,3,1,2,3,3,2]
[1,1,2,3,1,2,3,2,3]
[1,1,2,1,3,3,3,2,2]
[1,1,2,1,3,3,2,3,2]
[1,1,2,1,3,3,2,2,3]
[1,1,2,1,3,2,3,3,2]
[1,1,2,1,3,2,3,2,3]
[1,1,2,1,3,2,2,3,3]
[1,1,2,1,2,3,3,3,2]
[1,1,2,1,2,3,3,2,3]
[1,1,2,1,2,3,2,3,3]
[1,1,1,2,3,3,3,2,2]
[1,1,1,2,3,3,2,3,2]
[1,1,1,2,3,3,2,2,3]
[1,1,1,2,3,2,3,3,2]
[1,1,1,2,3,2,3,2,3]
[1,1,1,2,3,2,2,3,3]
[1,1,1,2,2,3,3,3,2]
[1,1,1,2,2,3,3,2,3]
[1,1,1,2,2,3,2,3,3]
[1,1,1,2,2,2,3,3,3]