AcWing 区间DP相关问题 1068. 环形石子合并

'''
核心思想
将原来序列拓展成2倍长度,在拓展区间上做区间DP
将环问题转换为线性区间问题
'''


N = int(input())
arr = list(map(int, input().split()))


# 把原来的序列拓展成2倍,然后在拓展之后的序列上进行区间DP,把换拆成链
arr = arr * 2


# dp(i,j)表示从i到j的区间中的石子合并成一个石子的所有方案中最小的开销
dp = [[0] * (2*N) for _ in range(2*N)]

s = [val for val in arr]
for i in range(1, len(s)):
    s[i] += s[i - 1]

for i in range(2*N - 1, -1, -1):
    for j in range(i, min(i+N, 2*N)):
        if i != j:
            dp[i][j] = 0x7fffffff

            for k in range(i, j):
                sum = s[j] if i == 0 else s[j] - s[i - 1]
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum)

# 筛选出长度是N的区间, 选最小的值
ans = 0x7fffffff
for i in range(N):
    ans = min(ans, dp[i][i+N-1])
print(ans)



# dp(i,j)表示从i到j的区间中的石子合并成一个石子的所有方案中最大的开销
dp = [[0] * (2*N) for _ in range(2*N)]

s = [val for val in arr]
for i in range(1, len(s)):
    s[i] += s[i - 1]

for i in range(2*N - 1, -1, -1):
    for j in range(i, min(i+N, 2*N)):
        if i != j:
            dp[i][j] = 0

            for k in range(i, j):
                sum = s[j] if i == 0 else s[j] - s[i - 1]
                dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + sum)

# 筛选出长度是N的区间, 选最大的值
ans = 0
for i in range(N):
    ans = max(ans, dp[i][i+N-1])
print(ans)

 

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