识别此算法:插槽和桩

时间:2009-02-06 12:42:23

标签: algorithm math

我有许多插槽和钉子直线排列。栓可以移动,需要每个都移动到一个槽。只有在采取所有钉子时,才能将槽留空。移动挂钉时,不允许穿过另一个挂钉。换句话说,必须保持钉的顺序。优选地,所有钉子移动的总距离应保持最小。应尽可能将钉子放在最近的可用插槽中。

我想知道的是:什么样的数学领域处理这样的问题?处理类似问题的任何众所周知的算法的名称是什么?我正在寻找Google饲料。一些关键字。

+--oooo-+--+---+---o--+------+--+-ooo+o-+-------o--+-----o-o-+-o

+ - Slots
o - Pegs


编辑:我认为这种可视化更有意义。它们是需要排列的两个独立的轨道。

Slots: +-------+--+---+------+------+--+----+--+----------+---------+--
Pegs:  ---oooo------------o--------------ooo-o---------o--------o-o---o

编辑:只是想明确说明广告位数可以大于,小于或等于钉子的数量。

6 个答案:

答案 0 :(得分:9)

我认为这是dynamic programming解决方案的经典素材。事实上,看一下“序列对齐”,这可能是该维基百科页面上另一个好的搜索词。

关键见解是:

想象一下,你将钉子作为挂钉位置列表(peg1:更多钉子)和插槽作为插槽位置列表(插槽1:更多插槽)。调用此问题(peg1:pegs,slot1:slots)。然后解决方案是插槽1和插槽1中的peg1。 (钉子,插槽)的解决方案,或者是(peg1:钉子,插槽)的解决方案。

这给出了如何解决它的递归定义。

或者在伪代码中(用函数编程风格编写),想象一下函数距离(peg,slot):

distance([]) = 0
distance((peg,slot):matches) = distance(peg,slot)+distance(matches)

solution(peg:[], slot:[]) = [(peg,slot)]
solution(peg:pegs, slot:slots) = if distance(a)<distance(b) then a else b
   where a = solution(peg:pegs, slots) and b=(peg,slot):solution(pegs, slots)

通过将距离组合到数据结构中,可以提高此解决方案的效率。

答案 1 :(得分:2)

我不知道这个问题的来源,但我很确定它是combinatorial optimization的一种形式,更具体地说,可以使用(integer) linear programming来解决。

答案 2 :(得分:1)

  

“所有钉子移动的总距离   应该保持在最低限度“

除非我遗漏了什么,否则这不是问题。

由于必须保持钉子的顺序,你可以只用钉子1,2,3 ......编号。

  

+ - 1234 - + - + --- + --- 5 - + ------ + - + - + 678 9 - + ------- 10 - + ----- 11-12 - + - 13

并且最终状态必须是插槽1中的钉1,插槽2中的钉2等等。

  

+ - 1 - + - 2 - + - 3 - + - 4 - + - 5 - + - 6 - + - 7 - + - 8 - + - 9 - + - 10 - + - 11 - + - 12 - + - 13 - +

无法跳过彼此的钉子并不重要,每个钉子必须从它的起点移动到最终点一定距离。 只要所有动作都朝着正确的方向并且一个挂钩永远不必备份 ,那么每个挂钩必须移动的距离是一个简单的常数(它没有' t取决于移动的顺序),以及这些距离的总和,你的成本函数也是不变的。

我认为这里不需要动态编程或线性编程优化问题。

如果你引入了一个挂钩并将其设置下来的成本,那么这里可能存在一个优化问题,但即使这样也许是微不足道的。

编辑以回应1800信息的评论

  

只有数量才有效   插槽数等于挂钉数量 -   在问题中没有假设这一点   声明 - 1800信息(2小时   前)

好的,我错过了。谢谢你指出我错过了什么。不过,我仍然不相信这是火箭科学。

假设#pegs&gt; #个洞。像上面那样计算最终状态,好像你有额外的洞一样;然后挑选最远移动的N个钉子并将它们从问题中移除:那些是不会被移动的。重新计算忽略那些钉子。

假设#holes&gt; #钉。正确的最终状态可能有也可能没有差距。如上所述计算最终状态,并查找相邻桩钉彼此相向移动的位置。这些是您可以将其分解为可以通过简单解决的子问题的点。当你在一个连续的子问题的两端都有洞时,还有一个额外的变量 - 最后的连续序列开始了。

是的,它比我刚开始时想象的要复杂一点,但它似乎仍然是一个小小的铅笔纸工作应该表明解决方案是一些易于理解和编码的循环。

答案 3 :(得分:0)

组合学。组合算法。具体的数学。 (也是的标题 唐纳德克努特an excellent and relevant book

答案 4 :(得分:0)

如果挂钩数= =插槽数,则只有一个解决方案。 第一个挂钩必须转到第一个插槽,下一个挂钩必须转到下一个插槽等。

数字是不同的,然后它稍微复杂一点,因为一个挂钩或插槽(我们可以移动哪一个并不重要)可以移动到很多地方。

蛮力: 假设对象的数量是m个钉和n个槽(可互换地),m <1。 Ñ

  1. 对于每个方式(n-m)个插槽都可以 选择(参考一些组合学 算法,看看如何做到这一点)
    1. 选择的(n-m)个插槽将为空。
    2. 用钉子填充剩余的m个槽。计算移动的距离。这与顶部讨论的情况相同。
  2. 选择最小移动距离的布置。
  3. 递归解决方案:

        int solve(int pegs, int *peg_x, int slots, int *slot_x)
        {
          if (slots > pegs )
            return solve(slots, slot_x, pegs, peg_x);
          if (slots == 0 || pegs==0)
            return 0; // Cannot move
    
          int option1 = INT_MAX, options2 = INT_MAX;
    
    
          if (pegs > slots ) // Can try skipping a peg
            option1 = solve(pegs-1, peg_x+1 /* Move over one element */
                              slots, slot_x);
          // pegs >= slots 
          option2 = solve(pegs-1, peg_x+1, slots-1, slot_x+1)
                    + abs(peg_x[0]-slot_x[0]);
          return min(option1, option2);
        }
    

    此解决方案仍然需要将结果存储在表中,以便不会多次解决子问题,从而成为动态解决方案。

    思考......会更新......

答案 5 :(得分:-1)

排队理论或数学......