铁路轨道的排列(堆栈实施)

时间:2015-05-09 15:31:49

标签: algorithm stack combinatorics catalan

Switching Network

编号为1,2,...,n的发动机位于左侧的线上,并且需要在发动机离开右侧轨道时重新排列(置换)发动机。支线轨道上的引擎可以留在那里或沿着正确的轨道发送,但它永远不会被发送回进入的轨道。例如,如果n = 3,并且我们在左侧轨道上编号为1,2,3的引擎,那么3首先进入支线轨道。然后我们可以发送2到分支,然后在右边的路上,然后在途中发送3,然后1,获得新的顺序1,3,2。 我们必须找到特定n的所有可能的排列。

对于n = 1,回答= 1;

对于n = 2回答= 2;

对于n = 3回答= 5;

没有找到任何一般性。 使用堆栈实现非常有用。

但欢迎任何解决方案。

P.S。这不是一个家庭作业问题,因为我是一个自学成才的人。

3 个答案:

答案 0 :(得分:2)

这是我尝试递归解决方案(参见Java代码中的注释):

private static int result = 0;
private static int n = 3;

public static void g(int right,int spur){
  if (right == n) // all trains are on the right track
    result++;
  else if (right + spur < n) // some trains are still on the left track
    g(right,spur + 1); // a train moved from the left track to the spur
  if (spur > 0) // at least one train is on the spur
    g(right + 1,spur - 1); // a train moved from the spur to the right track 
               // (also counts trains moving directly from the left to right track)
}

public static void main (String[] args){ 
  g(0,0);
  System.out.println(result); // 5
}

上面的递归解决方案实际上考虑了每种可能性。对于组合解,我们考虑在{ - 1}}运动的所有组合,其中相邻的这些运动相当于直接从左到右轨道的运动。有n个此类组合。现在让我们计算一下无效的那些:

考虑支柱2n choose n ins和(n - 1)的所有组合。所有这些都包括一个点(n + 1),其中列车被计为在没有列车的情况下离开支线。我们假设p在其前面有p个ins和k - 那么剩余的ins的数量是(k + 1);剩下的出局(n - 1 - k)

现在,在 (n + 1) - (k + 1) = (n - k)之后开始反转这些组合中的每一个组合的输入和输出,以便进入和离开。每个反转的部分都必须{{1} } ins和p出局。但是现在,如果我们在(n - k)之前和之后总计输入次数,我们会得到(n - 1 - k) ins和p。我们刚刚计算了k + (n - k) = n ins和(k + 1) + (n - 1 - k) = n出局无效的组合数。如果我们假设一个这样的组合可能没有被计算,理论上在n之后反转该组合,你会发现n ins和p组合的组合未计算在内。但根据定义,我们已将它们全部计算在内,因此我们假定的额外组合不可能存在。

总有效组合为(n - 1),加泰罗尼亚数字。

(改编自汤姆戴维斯的解释:http://mathcircle.berkeley.edu/BMC6/pdf0607/catalan.pdf

答案 1 :(得分:1)

首先,请注意,您可能会忽略将火车从直接传输到传出的可能性:这样的移动可以通过将火车移动到支线然后再移出来完成。

表示列车从入口移动到支线(,列车从支线移动到外出),你可以在列车的排列和n对正确平衡的列之间得到双射插入语。该陈述需要证明,但证明的唯一困难部分是证明没有两串平衡括号对应于相同的排列。这些字符串的数量是n'Catalan number,或者选择(2n,n)/(n + 1),其中choose(n,k)是从n中选择k项的方式的数量。< / p>

以下是计算解决方案的代码:

def perms(n):
    r = 1
    for i in xrange(1, n+1):
        r *= (n + i)
        r //= i
    return r // (n + 1)

您可以使用此代码生成所有排列,这也会暴露解决方案的加泰罗尼亚语性质。

def perms(n, i=0):
    if n == 0:
        yield []
    for k in xrange(n):
        for s in perms(k, i+1):
            for t in perms(n-k-1, i+k+1):
                yield s + [i] + t

print list(perms(4))

输出:

[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1],
 [0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3],
 [2, 1, 0, 3], [1, 2, 3, 0], [1, 3, 2, 0], [2, 1, 3, 0],
 [2, 3, 1, 0], [3, 2, 1, 0]]

答案 2 :(得分:0)

系统的状态可以通过给出左侧,正弦和右侧轨道中的3个(有序!)发动机列表来描述。鉴于状态,可以计算所有可能的移动。这创建了一个可能性树:树的根是初始状态,并且每个移动对应于导致新状态的分支。分支末尾的最终状态(叶子)是你在正确轨道上的最终位置。

所以,你必须建立和探索所有的树,最后你必须计算所有的叶子。树是一种常见的数据结构。

为了澄清,这种情况下的树不会替换堆栈。堆栈用于存储您的数据(引擎的位置);树用于跟踪算法的进度。每次有状态(树的节点)时,您必须分析数据(=堆栈的内容)并找到可能的移动。每次移动都是算法树中的一个分支,它会导致堆栈的新状态(因为引擎已经移动)。所以基本上你会有一个&#34;配置&#34;树的每个节点的3个堆栈。