20个元素的排列,符合某些规则

时间:2012-11-21 08:46:07

标签: algorithm permutation combinations pascal

我必须找到满足某些规则的20个元素的所有可能排列。例如,元素1永远不能位于3,4,6,7,8,12和17位置,元素2永远不能位于1,2,7,10,19位置,依此类推。目前我正在处理一个递归函数,该函数通过所有可能的排列并检查规则是否满足。这与10个元素(10!排列)完美配合,但是你可以想象这个算法不再可用于20个元素。有没有人知道一种更有效的方法来跳过不必要的排列? (我假设,从20!= 2.4E18可能的排列只有1-2Mio.将满足规则。

这就是我现在正在使用的(Pascal代码):

 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;

(“团队”是常数20和“h1”,“h2”是在其他地方定义的一些数组[1..20]。此外,定义了用于推导规则的全局二维数组“模式”这个数组可以看作是一个大的0-1矩阵,有n行和19列)

1 个答案:

答案 0 :(得分:0)

n!远不及多项式, 所以你的执行时间会 n越大,急剧增加。 如果“哪个号码可以/不可以”有某种模式 哪个插槽“然后你可以通过改进算法 使用它的结构,但你的问题不响 所以。

可能有一些帮助。首先,迭代 关于要放置的数字 - 而不是要填写的插槽:

对于每个数字1, .., n,请使用链接 他们可以进入的插槽列表。例如。 3号只能 进入插槽3,16,7,6 - 与n = 3的链表相邻。

维护所有n元素的“中心”数组(直接访问)。 每当你将一个数字(比如x)放到插槽p时,你就会 反转该中心阵列的第p个元素。

对您的n数字进行排序,以便在...的顶部排序 list是可以进入最少插槽数的数字, 并且在底部可以进入大多数数字 的插槽。

从列表顶部的数字开始并继续服用 使用这些链接列表的排列 - 将数字放入 未填充的插槽。这为您提供了最优的解决方案 指数时间。问题是指数级的。

您还可以使用子优化算法在多项式时间内运行,但不一定允许所有排列。