ACWing 区间DP相关问题 321. 棋盘分割

'''
二维区间DP
'''


import math
from functools import lru_cache

N = int(input())
grid = []
for _ in range(8):
    l = list(map(int, input().split()))
    grid.append(l)

pre_sum = [[val for val in grid[i]] for i in range(8)]
for i in range(8):
    for j in range(1, 8):
        pre_sum[i][j] += pre_sum[i][j - 1]
for i in range(1, 8):
    for j in range(8):
        pre_sum[i][j] += pre_sum[i - 1][j]


@lru_cache(typed=False, maxsize=128000000)
def get_sum(i1, j1, i2, j2):
    val1 = 0 if i1 - 1 < 0 else pre_sum[i1 - 1][j2]
    val2 = 0 if j1 - 1 < 0 else pre_sum[i2][j1 - 1]
    val3 = 0 if i1 - 1 < 0 or j1 - 1 < 0 else pre_sum[i1 - 1][j1 - 1]
    return pre_sum[i2][j2] - val1 - val2 + val3


# 经过公式化简,目标是要让每个分块的xi的平方和最小
# dp(i1, j1, i2, j2)表示左上角是i1, j1 右下角是i2, j2的矩形切分k次的所有方案的分块价值平方和的最小值

@lru_cache(typed=False, maxsize=128000000)
def dp(i1, j1, i2, j2, k):
    if k == 0:
        return get_sum(i1, j1, i2, j2) * get_sum(i1, j1, i2, j2)

    if i2 == i1 and j2 == j1:
        # 无法切分
        return 0x7fffffff

    # 纵着切分
    ans = 0x7fffffff
    for i in range(i1, i2):
        val1 = get_sum(i1, j1, i, j2) * get_sum(i1, j1, i, j2) + dp(i + 1, j1, i2, j2, k - 1)
        val2 = get_sum(i + 1, j1, i2, j2) * get_sum(i + 1, j1, i2, j2) + dp(i1, j1, i, j2, k - 1)
        ans = min(ans, val1, val2)

    # 横着切分
    for j in range(j1, j2):
        val1 = get_sum(i1, j1, i2, j) * get_sum(i1, j1, i2, j) + dp(i1, j + 1, i2, j2, k - 1)
        val2 = get_sum(i1, j + 1, i2, j2) * get_sum(i1, j + 1, i2, j2) + dp(i1, j1, i2, j, k - 1)
        ans = min(ans, val1, val2)

    return ans


total = 0
for i in range(8):
    total += sum(grid[i])
mean = total / N

square_sum = dp(0, 0, 7, 7, N - 1)
ans = math.sqrt((square_sum - N * mean * mean) / N)

print('%.3f' % ans)

 

你可能感兴趣的:(ACWing,区间DP相关问题,算法)