Python 具有挑战性的动态规划问题

Python 具有挑战性的动态规划问题,python,complexity-theory,dynamic-programming,Python,Complexity Theory,Dynamic Programming,这是一个我需要解决的计算机视觉问题的缓和版本。假设给定了参数n,q,并且必须计算将整数0..(q-1)赋值给n×n网格元素的方法的数量,以便对于每个赋值,以下都是真的 没有两个邻居(水平或垂直)获得相同的值 位置(i,j)处的值为0 位置(k,l)处的值为0 因为没有给出(i,j,k,l),所以输出应该是上面的一组求值,对于(i,j,k,l)的每个有效设置一个求值 下面是一种暴力手段。我们的目标是得到一个适用于q0 else-1的高效算法 右=网格[r][c-1],如果c 0,则为-1 底部=网

这是一个我需要解决的计算机视觉问题的缓和版本。假设给定了参数n,q,并且必须计算将整数0..(q-1)赋值给n×n网格元素的方法的数量,以便对于每个赋值,以下都是真的

  • 没有两个邻居(水平或垂直)获得相同的值
  • 位置(i,j)处的值为0
  • 位置(k,l)处的值为0
  • 因为没有给出(i,j,k,l),所以输出应该是上面的一组求值,对于(i,j,k,l)的每个有效设置一个求值

    下面是一种暴力手段。我们的目标是得到一个适用于q0 else-1的高效算法 右=网格[r][c-1],如果c 0,则为-1 底部=网格[r+1][c],如果r 更新11/11
    我也在TopCoder上问过这个问题,他们的解决方案是我迄今为止看到的最有效的解决方案(根据作者的估计,对于n=10,任意q,大约3个小时)

    这不是一个答案,只是对讨论的贡献,讨论太长,无法发表评论

    tl;博士任何归结为“计算可能性并计算它们”的算法,如Eric Lippert的算法或蛮力方法,都无法实现@Yaroslav的
    q=4
    目标。从芥末柱的顶部单元格开始。我们只需要担心bread列的相邻单元格,它们最多有2个唯一值。为芥末色列选择第三个数字。考虑芥菜柱的第二个细胞。我们必须考虑以前的芥菜细胞和2个相邻的面包细胞,总共有最多3个独特的值。选择第四个值。继续填写芥末栏

    我们最多有2列包含硬编码单元格0。因此,使用芥末柱,我们可以制作至少6个面包柱,每个面包柱大约有
    10^36
    个解,总共至少有
    10^216
    个有效解,给或取一个数量级的舍入误差

    根据维基百科,宇宙中大约有10^80个原子


    因此,要更聪明。

    也许这听起来太简单了,但它确实有效。将值随机分布到所有单元格,直到只有两个单元格为空。测试所有值的邻接性。计算成功转换与所有转换的平均百分比,直到差异降至可接受的范围内


    风险为零,处于风险中的只是一点运行时间。

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

    现在不要考虑最后两个约束(<代码>(i,j)< /代码>和<代码>(k,l)< /代码>)。

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


    第二列有多少个选项<代码>(q-1)用于顶部单元格(1,2),但如果(1,2)/(2,1)具有或不具有相同的颜色,则该单元格(2,2)的
    q-1
    q-2

    (3,2)也是一样:
    q-1
    q-2
    解决方案

    我们可以看到,我们有一个可能性的二叉树,我们需要在这棵树上求和。让我们假设左边的子对象总是“顶部和左侧的颜色相同”,右边的子对象是“不同的颜色”

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

    但是现在让我们考虑第二列着色的概率分布:如果我们想迭代这个过程,我们需要在第二列上有均匀的分布,这就像第一个颜色不存在一样,在前两列的所有颜色中,我们可以说

    1/q
    其中的第二列的顶部单元格中有颜色0

    没有统一的分布,这是不可能的

    问题是:分布是否均匀

    回答: 通过构建第一列、第二列、第一列和第三列,我们可以得到相同数量的解。在这种情况下,第二列的分布是均匀的,因此在第一种情况下也是如此

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


    我将尝试在此基础上发展并建立一个通用公式(因为树的大小为2^n,我们不想明确探讨它)。

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

  • 值1..q是可互换的-它们可以是字母,结果相同
  • 没有邻居能与之匹敌的限制是非常温和的,因此暴力手段将过于昂贵。即使您知道除了一个单元格以外的所有单元格中的值,对于q>8,仍然存在至少q-8的可能性
  • 它的输出将相当长——每一组i,j,k,l都需要一条线。组合的数量类似于n2(n2-3),因为两个固定零可以是除彼此相邻之外的任何地方,除非它们不需要遵守第一条规则。对于n=100和q=18,最大困难的情况是~1004=1亿。所以这是你的最小复杂性,并且是不可避免的,因为问题是目前所说的
  • 有一些简单的情况——当q=2时,有两个可能的棋盘,因此对于任何给定的零对,答案都是1
  • 第3点将整个程序O(n2(n2-3))设置为最小值,并且还建议对于每对零a,您需要一些合理有效的东西
    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]