【问题标题】:Challenging dynamic programming problem具有挑战性的动态规划问题
【发布时间】:2011-05-07 12:06:18
【问题描述】:

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

  1. 没有两个邻居(水平或垂直)获得相同的值。
  2. 位置 (i,j) 的值为 0
  3. 位置 (k,l) 的值为 0

由于没有给出 (i,j,k,l),因此输出应该是上面的评估数组,每个有效设置对应 (i,j,k,l)

下面是蛮力方法。目标是获得一种适用于 q

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,任意 q 大约需要 3 小时)

【问题讨论】:

  • @Yaroslav:如果您将代码缩进四个空格,它将被格式化。您可以使用编辑器上方的“代码示例”按钮。只需突出显示您的代码并点击上面带有二进制数字的按钮。
  • 看不懂and value at positions (i,j), (k,l) is 0, for every combination of i,j,k,l
  • Eric Lippert 的博客最近有一个关于这个主题的系列。 Part 12345.
  • 此外,所有着色定理都适用于任意地图,但这仅适用于简单的网格。给这个网格上色非常简单,应该有一种相当直接的方法来计算所有可能的颜色。
  • 洛伊克和贝利撒留:是的,我将这两个位置的颜色固定为零。由于没有给出 (i,j,k,l),我必须遍历 (i,j,k,l) 的每个组合,并给出如果特定的 i,j,k,l提供了组合

标签: python complexity-theory dynamic-programming


【解决方案1】:

我不是数学家,但我突然想到这个问题应该有一个解析解,即:

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

然后算出这些解中有多少在 (i,j) 中有 0,这应该是 1/Q 的分数。

然后根据曼哈顿距离 |ik|+|jl| 以及到棋盘边缘的距离和这些距离的“奇偶性”,计算出在 (k,l) 中有多少剩余解决方案为 0,如距离可除被 2 整除,被 3 整除,被 Q 整除。

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

【讨论】:

  • 其实没有一个简单的着色数公式——它也被称为彩色多项式,这里有一个13x13网格的版本——staff.hs-mittweida.de/~peter/research/results/…
  • 我更多地考虑从无限晶格开始以及两个边缘和诱导零的位错。 50 年前,晶体学在纸上处理过这个问题;-)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    一些可能对其他回答者也有帮助的观察:

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

    第 3 点使整个程序 O( n2(n2-3) ) 成为最小值,并且还建议您需要对每个程序进行合理有效的处理简单地编写 1 亿行而无需任何计算的一对零将需要一段时间。作为参考,以每行 1 秒计算,即 1x108s ~ 3 年,或 12 核盒子上的 3 个月。

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

    【讨论】:

    • 对于 n=18,输出值约为 100k,而不是 100 mil
    【解决方案4】:

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

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

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


    第二列有多少选择? (q-1) 用于顶部单元格 (1,2),然后 q-1q-2 用于单元格 (2,2) 如果 (1,2)/(2,1) 颜色相同或不同。

    对于 (3,2) 也是如此:q-1q-2 解决方案。

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

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

    但是现在让我们考虑第二列着色的概率分布:如果我们想要迭代该过程,我们需要在第二列上具有均匀分布,这就像第一列从未存在过一样前两列的颜色我们可以说像1/q 这样的东西在第二列的顶部单元格中有颜色0。

    没有均匀分布是不可能的。

    问题:分布均匀吗?

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

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

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

    【讨论】:

    • 不太确定我是否理解这个问题,但一种标准的基于列的颜色计数方法是拥有一个 (q^n)x(q^n) 矩阵 A,其中第 ij 项为 1如果第 2 列的第 j 种颜色与第 1 列的第 i 种颜色兼容。然后 A^(n-1) 的元素之和给出正确颜色的数量
    • @Yaroslav Bulatov :我不知道这种方法,但它的复杂性似乎至少为 (q^n)^2。我正在尝试找到一个可以在 O(q*n) 中计算的公式
    【解决方案5】:

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

    风险归零,有风险的只是一点运行时间。

    【讨论】:

    • 对大箱子的想法很好。我会为 q=2 之类的琐碎情况添加一些处理,即组合的数量很少,这种估计会不准确,但在其他方面非常好。
    • @Yaroslav,你对近似算法感兴趣吗?无论如何,聪明的想法@Harryooo。任何关于 O(您需要多少次试验)以达到给定利润的分析?
    • 是的,我对精确感兴趣。实际上,我想要精确的原因是能够针对小 n 的精确结果来测试像 Harry's 这样的近似算法
    • 对于 n=10,q=3 大约有 10^20 个正确的分配和 10^47 个总分配,所以这个方法需要大约 10^27 次调用才能获得一次成功
    【解决方案6】:

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

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

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

    现在考虑由缓冲列(称为芥末列)分隔的任意两个有效列(称为面包列)。这是一个简单的算法,可以在 q &gt;= 4 时为芥末列找到一组有效值。从芥末列的顶部单元格开始。我们只需要担心面包列的相邻单元格最多有 2 个唯一值。为芥末列选择任何第三个数字。考虑芥末列的第二个单元格。我们必须考虑前一个芥末细胞和两个相邻的面包细胞,总共最多有 3 个唯一值。选择第 4 个值。继续填写芥末栏。

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

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

    因此,要聪明一点。

    【讨论】:

      猜你喜欢
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      相关资源
      最近更新 更多