我必须找到满足某些规则的 20 个元素的所有可能排列。例如,元素 1 永远不能位于位置 3、4、6、7、8、12 和 17,元素 2 永远不能位于位置 1、2、7、10、19 等等。目前,我正在使用一个递归函数,该函数遍历所有可能的排列并检查规则是否得到满足。这适用于 10 个元素(10 个!排列),但正如您可以想象的那样,该算法不再适用于 20 个元素。有谁知道跳过不需要的排列的更有效的方法?(我假设,从 20!=2.4E18 可能的排列中,只有 1-2 Mio。将满足规则。
这就是我现在使用的(帕斯卡代码):
procedure permu(p:feldtyp; ka:bereich);
var
i,h : bereich;
label skip;
begin
if ka=teams then begin
//execute certain tests, skip the output part if the tests fail
for i:=1 to ka do if ((hh11[P[i]]+hh21[i])<>(ka-1)) or
((patterns[h1[P[i]]][teams-1]=patterns[h2[i]][1]) and ((patterns[h1[P[i]]][teams-1]=patterns[h1[P[i]]][1])=(patterns[h2[i]][teams-1]=patterns[h2[i]][1]))) or
((patterns[h1[P[i]]][teams-1]<>patterns[h2[i]][1]) and ((patterns[h1[P[i]]][teams-1]=patterns[h1[P[i]]][1])<>(patterns[h2[i]][teams-1]=patterns[h2[i]][1]))) or
((patterns[h1[P[i]]][teams-1]<>patterns[h2[i]][1]) and ((patterns[h1[P[i]]][teams-1]=patterns[h1[P[i]]][1]) and (patterns[h2[i]][teams-1]=patterns[h2[i]][1]))) or
((patterns[h1[P[i]]][teams-1]=patterns[h2[i]][1]) and ((patterns[h1[P[i]]][teams-2]=patterns[h1[P[i]]][teams-3]) or (patterns[h2[i]][2]=patterns[h2[i]][3]))) or
((patterns[h1[P[i]]][teams-1]=patterns[h1[P[i]]][teams-2]) and (patterns[h2[i]][1]=patterns[h2[i]][2]))
then goto skip;
//all tests passed, write permutation
// ...
skip:
end
else begin
for i := ka to teams do begin
h := P[i];
P[i] := p[ka];
P[ka] := h;
permu(p, ka+1);
end;
end;
end;
(“teams”是常数 20,“h1”、“h2”是在其他地方定义的一些数组 [1..20]。此外,定义了一个全局二维数组“patterns”,用于导出规则。这个数组可以看成一个n行19列的大0-1矩阵)