挑战动态编程问题

时间:2010-11-09 20:37:48

标签: python complexity-theory dynamic-programming

这是我需要解决的计算机视觉问题的低调版本。假设给你参数n,q并且必须计算将整数0 ..(q-1)分配给n-by-n网格的元素的方式的数量,以便对于每个赋值,以下都是真的

  1. 没有两个邻居(水平或垂直)获得相同的值。
  2. 位置(i,j)的值为0
  3. 位置(k,l)的值为0
  4. 由于没有给出(i,j,k,l),输出应该是上面的一个评估数组,每一个有效设置为(i,j,k,l)

    蛮力方法如下。目标是获得一种适用于q <= 100且n <= 18的有效算法。

    def tuples(n,q):
      return [[a,]+b for a in range(q) for b in tuples(n-1,q)] if n>1 else [[a] for a in range(q)]
    
    def isvalid(t,n):
      grid=[t[n*i:n*(i+1)] for i in range(n)];
      for r in range(n):
        for c in range(n):
          v=grid[r][c]
          left=grid[r][c-1] if c>0 else -1
          right=grid[r][c-1] if c<n-1 else -1
          top=grid[r-1][c] if r > 0 else -1
          bottom=grid[r+1][c] if r < n-1 else -1
          if v==left or v==right or v==top or v==bottom:
            return False
      return True
    
    def count(n,q):
      result=[]
      for pos1 in range(n**2):
        for pos2 in range(n**2):
          total=0
          for t in tuples(n**2,q):
            if t[pos1]==0 and t[pos2]==0 and isvalid(t,n):
              total+=1
    
          result.append(total)
    
      return result
    
    assert count(2,2)==[1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1]
    

    更新11/11 我也在TopCoder forums上问了这个问题,他们的解决方案是迄今为止我见过的最有效的解决方案(对于n = 10大约3个小时,任何q,来自作者的估计)

6 个答案:

答案 0 :(得分:3)

也许这听起来太简单了,但确实有效。随机地将值分配给所有单元格,直到只有两个为空。测试所有值的邻接性。计算成功演员阵容与所有演员阵容的平均值,直到差异降到可接受的范围内为止。

风险变为零,风险的风险只有一点运行时间。

答案 1 :(得分:2)

这不是一个答案,只是对讨论的贡献,这对评论来说太长了。

TL;博士;任何归结为“计算可能性并计算它们”的算法,例如Eric Lippert或蛮力方法都不适用于@ Yaroslav的q <= 100n <= 18目标。

让我们首先考虑一个n x 1列。这一列有多少个有效编号?对于第一个单元格,我们可以在q个数字之间进行选择。由于我们不能垂直重复,我们可以在第二个单元格的q - 1个数字之间进行选择,因此在第三个单元格中选择q - 1个数字,依此类推。对于q == 100n == 18,这意味着q * (q - 1) ^ (n - 1) = 100 * 99 ^ 17有效着色非常粗略10 ^ 36

现在考虑由缓冲区列分隔的任何两个有效列(称为面包列)(称为芥末列)。这是一个简单的算法,用于在q >= 4时查找芥末色谱柱的有效值集。从芥末色谱柱的顶部单元开始。我们只需要担心面包列的相邻单元格,它们最多有2个唯一值。选择芥末色谱柱的任何第三个数字。考虑芥末色谱柱的第二个细胞。我们必须考虑先前的芥菜细胞和2个相邻的面包细胞,总共最多3个独特的值。选择第4个值。继续填写芥末色谱柱。

我们最多有2列包含0的硬编码单元。因此,使用芥末色谱柱,我们可以生成至少6个面包列,每个列具有大约10 ^ 36个解决方案,总计至少{{1}有效的解决方案,为舍入错误提供或采取一个数量级。

根据维基百科的说法,宇宙中有10 ^ 216个原子。

因此,要更聪明。

答案 2 :(得分:1)

  

更新11/11我也在TopCoder论坛上问了这个问题,他们的解决方案是迄今为止我见过的最有效的解决方案(约为41小时,n = 10,任何q,来自作者的估计)

我是作者。不是41,只有3个令人尴尬的可并行化CPU小时。我有counted对称性。对于n = 10,只有675个真正不同的(i,j)和(k,l)对。我的程序每个需要大约16秒。

答案 3 :(得分:0)

我正在根据Dave Aaron Smith对讨论的贡献来建立一个贡献。

我们暂时不考虑最后两个约束((i,j)(k,l))。

只有一列(nx1),解决方案为q * (q - 1) ^ (n - 1)

<小时/> 第二列有多少选择?最高单元格(1,2)(q-1),但是如果(1,2)/(2,1)有或没有q-1q-2单元格(2,2)相同的颜色。

(3,2)同样的事情:q-1q-2解决方案。

我们可以看到我们有一个可能性的二叉树,我们需要总结那棵树。让我们假设左孩子总是“在上面和左边是相同的颜色”而右孩子是“不同的颜色”。

通过在树上计算左列创建此类配置的可能性数量以及我们着色的新单元格的可能性数量,我们将计算着色两列的可能性数量。

但现在让我们考虑第二列着色的概率分布:如果我们想要迭代过程,我们需要在第二列上有一个统一的分布,它就像第一列中从未存在的那样,并且在所有前两列的着色我们可以说它们1/q之类的东西在第二列的顶部单元格中有颜色0。

如果没有统一的分布,就不可能。

问题:分布均匀吗?

答案: 我们将通过首先构建第一列,然后是第一列,然后是第三列来获得相同数量的解决方案。在这种情况下,第二列的分布是均匀的,因此它也是第一种情况。

我们现在可以应用相同的“树形思想”来计算第三列的可能性数量。

我将尝试开发并构建一个通用公式(因为树的大小为2 ^ n,我们不想明确地探索它)。

答案 4 :(得分:0)

一些可能有助于其他回答者的观察结果:

  1. 值1..q可以互换 - 它们可以是字母,结果也是一样的。
  2. 没有邻居匹配的限制是非常温和的,因此蛮​​力方法将过于昂贵。即使你知道除了一个单元格以外的所有值,q> 8时仍然至少有q-8种可能性。
  3. 这个输出会很长 - 每一组i,j,k,l都需要一条线。组合的数量类似于n 2 (n 2 -3),因为两个固定的零可以是除了彼此相邻之外的任何地方,除非他们不需要遵守第一条规则。对于n = 100和q = 18,最大硬情况,这是~100 4 = 1亿。因此,这是您的最低复杂性,并且由于目前存在问题而无法避免。
  4. 有一些简单的情况 - 当q = 2时,有两个可能的棋盘格,因此对于任何给定的零对,答案是1。

第3点使整个程序O(n 2 (n 2 -3))最小化,并且还表明你需要一些合理有效的东西简单地写1亿行而不进行任何计算需要一段时间。作为参考,每行第二行,即1x10 8 s~3年,或12核盒子上的3个月。

我怀疑给出一对零的优雅答案,但我不确定是否有解析解决方案。鉴于您可以使用2或3种颜色(取决于零的位置),您可以将地图拆分为一系列区域,每个区域仅使用2或3种颜色,然后它只是不同组合的数量每个区域的q或q(qC2或qC3)中的2或3乘以区域的数量,乘以分割地图的方式的数量。

答案 5 :(得分:0)

我不是数学家,但在我看来应该有一个解决这个问题的解决方案,即:

首先,计算现在许多不同的颜色可能用于具有Q颜色的NxN板(包括定义为具有共同边缘的相邻颜色不相同的邻居)。这应该是非常简单的公式。

然后弄清楚这些解决方案中有多少在(i,j)中有0,这应该是1 / Q的分数。

然后根据曼哈顿距离| ik | + | jl |计算剩余解决方案中有多少个(k,l),并且可能距离板边缘和这些距离的“奇偶校验”,如距离可分距2,可被3整除,可被Q整除。

最后一部分是最难的,但我认为如果你真的擅长数学,它仍然可行。