在网格中回溯

时间:2017-05-04 12:09:28

标签: python algorithm backtracking recursive-backtracking

让我们说有一个1和0的2D网格,例如 -

0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0

网格已经崩溃了#34;形成一个较少的行和1个较少的列的较小网格,因此上面的例子将是"折叠"形成一个3行3列的网格。

新值由以下规则确定 -

new_grid[i][j] is dependent on 
  i) old_grid[i][j], 
 ii) old_grid[i][j+1], 
iii) old_grid[i+1][j] 
 iv) old_grid[i+1][j+1]

If exactly one of the above values are 1, then new_grid[i][j] will be 1, else 0.

因此,对于示例网格,[0][0], [0][1], [1][0] and [1][1]中只有[0][1]1,因此新网格中的[0][0]将为1.同样,[0][1], [0][2], [1][1] and [1][2] 1}},[0][1] and [1][2]都是1,因此[0][1]中的new_grid将为0。

输入以new_grid值的形式给出。我必须找出old_grid的可能配置数量,以便通过提供的折叠规则new_grid成为可能。

我的方法

我目前想到的回溯解决方案是这样的 -

  1. 为旧网格中的每个1值单元格标识虚构的2X2框,这对应于新网格中的相应单元格。

  2. 所有这些框都只包含一个值为1的单元格,因此将1放在每个框中的随机单元格中。

  3. 递归检查在随机单元格中放置1是否确保每个框仍然只保留一个值为1的单元格。

  4. 如果最终获得网格配置,其中每个框只包含一个值为1的单元格,请检查配置是否可以“折叠”#34;获得新网格。

  5. 如果没有,则使用值为1的其他单元重复此过程。

  6. 如果旧网格中有一些单元格不属于任何"框#34;那么它们就是我所说的"并不重要" 34;细胞

    例如 -

    1 1 
    0 0
    

    对于上述new_gridold_grid可以是 -

    1 0 1
    0 0 0 
    0 0 0           
    

    1 0 1
    0 0 0
    1 1 1
    

    最后一行的单元格"不重要"因为它们不属于任何2X2框,所以它们都可以10 s为有效配置(我认为这是我们可以灵活操纵它们的程度,虽然我不确定)。

    我的问题是这个 - 这个算法在增长中可能是指数级的,并且它会花费大量时间来表示50X10

    还有其他方法可以解决这个问题吗?或者是否有任何聪明的算法不能通过每个可能的配置来计算它们?

1 个答案:

答案 0 :(得分:0)

嗯,所以我想到了像这样的2x3 newGrid:

newGrid: 0 1 0
         0 0 0

这需要由以下3x4 oldGrid之一生成:
每个_可以是10

oldGrid 1: _ 0 1 _
           _ 0 0 _
           _ _ _ _

oldGrid 2: _ 1 0 _
           _ 0 0 _
           _ _ _ _

oldGrid 3: _ 0 0 _
           _ 1 0 _
           _ _ _ _

oldGrid 4: _ 0 0 _
           _ 0 1 _
           _ _ _ _

其余的8个斑点可以2 ^ 8的方式填充。 因此答案将是4 * 2 ^ 8

但是,想象一下newGrid是否有多个1:

newGrid: 1 1 0
         0 0 0

将有以下8个oldGrid:

oldGrid 1: 1 0 _ _
           0 0 _ _
           _ _ _ _

oldGrid 2: 0 1 _ _
           0 0 _ _
           _ _ _ _

oldGrid 3: 0 0 _ _
           1 0 _ _
           _ _ _ _

oldGrid 4: 0 0 _ _
           0 1 _ _
           _ _ _ _

oldGrid 5: _ 1 0 _
           _ 0 0 _
           _ _ _ _

oldGrid 6: _ 0 1 _
           _ 0 0 _
           _ _ _ _

oldGrid 7: _ 0 0 _
           _ 1 0 _
           _ _ _ _

oldGrid 8: _ 0 0 _
           _ 0 1 _
           _ _ _ _

来自oldGrid 1,我将产生2 ^ 8个组合。但是请注意,其中一些将与oldGrid 6产生的解决方案相同。就是这样的:

oldGrid 1.1: 1 0 1 _
             0 0 0 _
             _ _ _ _

它有2 ^ 6个解决方案。

因此oldGrid 1的解决方案2 ^ 8-2 ^ 6与oldGrid 6不冲突。
并且oldGrid 6有2 ^ 6个与oldGrid 1不冲突的解决方案。
并且它们一起具有(2 ^ 8-2 ^ 6)+(2 ^ 8-2 ^ 6)+ 2 ^ 6解。

1和6、1和8、2和5、3和6、3和8、4和7具有冲突的解空间,每个解空间都有2 ^ 6。

我认为这意味着解决方案的数量为8 * 2 ^ 8-6 * 2 ^ 6。
那就是:

numberOfSolutions = numberOf1s * 4 * 2^(oldGridSize-4) - overlappingSolutionsCount
overlappingSolutionsCount = numberOfOverlappingPairs * 2^(oldGridSize-4-overlapAreaSize)  

如何计算重叠

function countOverlappingSolutions(newGrid: an MxN matrix) {
    result = 0
    oldGridSize = (M+1) * (N+1)
    for each pair of 1s in the newGrid:
        let manhattanDistance = manhattan distance between the 1s in the pair
        let overlapAreaSize = 0

        if the 1s are in the same row or column
            if manhattanDistance == 1:
                overlapSize = 2
        else if manhattanDistance == 2
            overlapAreaSize = 1

        result += 2^(oldGridSize -4 -overlapAreaSize)

    return result
}

最终算法:

let newGrid be a MxN matrix
let numberOf1s = number of 1s in newGrid
let oldGridSize = (M+1) * (N+1)

result = numberOf1s * 4 * 2^(oldGridSize - 4) - countOverlappingSolutions(newGrid)

我无法努力编写python代码,但我希望解决方案是正确的和/或能说明问题的方式