曼哈顿最坏情况排除


20

想象一下WH的正方形正方形网格,它们以环形环绕。将项目如下放置到网格上。

第一项可以放置在任何正方形上,但是后续项一定不能在任何先前项的曼哈顿距离 R内(也称为范围R冯·诺伊曼邻域)。仔细选择位置可以在没有更多有效位置之前将大量项目装配到网格上。但是,请考虑相反的目标:可以放置的且没有其他有效位置的最少物品数是多少?

这是半径5的禁区:

半径5禁区

这是另一个半径5排除区域,这次是在边缘附近,因此包裹行为很明显:

包装半径5禁区

输入值

三个整数:

  • W:网格宽度(正整数)
  • H:网格高度(正整数)
  • R:禁区半径(非负整数)

输出量

整数N,它是可以放置的最小项数,可以防止任何其他有效的放置。

细节

  • 半径为零时,排除区域为1平方(放置该项目的区域)。
  • 半径N排除了在N个正交步长中可以到达的区域(请记住边缘以环形方式缠绕)。

您的代码必须适用于琐碎的R = 0情况,但不需要适用于W = 0或H = 0。

您的代码还必须处理R > WR > H的情况

时限和测试用例

您的代码必须能够处理所有测试用例,并且每个测试用例必须在5分钟内完成。这应该很容易(示例JavaScript解决方案每个测试用例需要花费几秒钟的时间)。期限主要是为了排除极端暴力手段。示例方法仍然是蛮力的。

如果您的代码在一台计算机上在5分钟内完成,但在另一台计算机上没有完成,这将足够接近。

输入形式的测试用例:输出为W H R : N

5 4 4 : 1
5 4 3 : 2
5 4 2 : 2
5 4 1 : 5

7 5 5 : 1
7 5 4 : 2
7 5 3 : 2
7 5 2 : 4

8 8 8 : 1
8 8 7 : 2
8 8 6 : 2
8 8 5 : 2
8 8 4 : 2
8 8 3 : 4

 7  6  4 : 2
 7  6  2 : 4
11  7  4 : 3
11  9  4 : 4
13 13  6 : 3
11 11  5 : 3
15 14  7 : 2
16 16  8 : 2

片段帮助可视化和玩转想法

示例(无胶)解决方案

只是一个小输出的示例(半径不小于宽度和高度的结果)。可以处理任何测试用例,但会超时并放弃大多数较大的用例。


4
很棒的代码片段!
舒展疯子2015年

@StretchManiac谢谢:)我正尝试学习JavaScript,所以欢迎任何反馈
trichoplax

1
那是一个非常不错的片段。我也喜欢那种配色方案。是从调色板上来的吗?
英里

@miles谢谢-颜色只是猜测,然后进行了一些微调(但不多-它们仍然都是3个字符的颜色代码,而不是6个)。您可以在代码段的第三行中看到使用的颜色。
trichoplax

Answers:


5

Python 2中,216 ×182字节

def f(W,H,R):L={(i%W,i/W)for i in range(W*H)};M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R};g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1]);return g(M)

输入类似f(16,16,8)。使用与@trichoplax的sample几乎相同的算法,但带有集合。最初,我没有将第一个项目放置在(0, 0),但这在最近的几个案例中使它感到窒息。

以上所有情况都在10秒内完成,远远低于限制。实际上,案例足够小,以至于我有一点空间来降低效率,从而使我可以删除检查重复状态的支票。

(感谢@trichoplax提供高尔夫帮助)

展开:

def f(W,H,R):
  # All cells
  L={(i%W,i/W)for i in range(W*H)}                 

  # Mask: Complement of exclusion zone around (0, 0) 
  M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R}

  # Place recursively
  g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1])
  return g(M)

2

Python 3中,270 262 260 251 246 226

(感谢Sp3000提供的:

  • -~ 而不是 +1这使我 在最后一行之后失去了一个空格return
  • 在周围失去多余的括号 W*H
  • lambdas ...
  • 将所有内容放在一起。
  • python模%为负数提供正结果,以节省另外20个字节)

这是移植到Python 3中的问题的JavaScript示例答案。

为了避免传递太多的函数参数,我将两个支持函数移到了calculate函数内,以便它们共享其作用域。我还将这些功能中的每一个都压缩为一行,以避免缩进的成本。

说明

这种相当蛮力的方法将第一个项目放在(0,0),然后标记所有排除的正方形。然后,它将在所有剩余的有效正方形上递归放置一个项目,直到排除所有正方形为止,并返回所需的最小项目数。

高尔夫代码:

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

取消程式码:

def calculate(W, H, R):
    starting_min = W * H + 1
    cells = [0] * (W * H)
    grid_state = grid_with_item_added(cells, 0, 0, W, H, R)
    return min_from_here(grid_state, starting_min, W, H, R) + 1

def min_from_here(grid_state, starting_min, W, H, R):
    no_cells = True
    min = starting_min
    for x in range(W):
        for y in range(H):
            if grid_state[x + W * y] == 0:
                no_cells = False
                new_grid_state = grid_with_item_added(grid_state, x, y, W, H, R)
                m = min_from_here(new_grid_state, starting_min, W, H, R)
                if m < min:
                    min = m

    if no_cells:
        return 0
    else:
        return min + 1

def grid_with_item_added(grid_state, x, y, W, H, R):
    grid = grid_state[:]
    for a in range(W):
        for b in range(H):
            if manhattan_distance(a, b, x, y, W, H) <= R:
                grid[a + W * b] = 1

    return grid

def manhattan_distance(a, b, c, d, W, H):
    horizontal = min(abs(W + c - a) % W, abs(W + a - c) % W)
    vertical = min(abs(H + d - b) % H, abs(H + b - d) % H)
    return horizontal + vertical


if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(calculate(int(arguments[0]), int(arguments[1]), int(arguments[2])))

非高尔夫代码定义了一个函数,还包括允许从命令行调用它的代码。高尔夫球代码仅定义了功能,足以解决标准代码高尔夫球问题

如果您想从命令行测试高尔夫代码,则此处包含命令行处理(但不是高尔夫):

命令行可测试的高尔夫代码

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(C(int(arguments[0]), int(arguments[1]), int(arguments[2])))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.