动态规划
题目一:Atcoder 332 E题。
题目大意。给定一个长度为N的数组A,把该数组分为D组,每组可以为空,求最小化的方差。1<=D<=N<15。0<A[i]<1e9。
从数据范围来看N=15。考虑状压DP。和枚举子集。
代码一TLE。>2000ms
N, D = MI()
A = LI()
dp = [[0 for _ in range(D + 1)] for _ in range(1 << N)]
ave = sum(A) / D
for i in range(1 << N):
y = 0
for j in range(N):
if i & (1 << j):
y += A[j]
dp[i][1] = pow(y - ave, 2)
for j in range(2, D + 1):
dp[i][j] = dp[i][j - 1] + dp[0][1]
x = i
while x > 0:
dp[i][j] = min(dp[i][j], dp[i - x][j - 1] + dp[x][1])
x = (x - 1) & i
rst = dp[-1][D] / D
print('%.15f' % rst)
代码二 100ms
# ABC332E Lucky bag O(3^N)
# Reference: https://atcoder.jp/contests/abc332/editorial/7947
# 入力受取
N, D = map(int, input().split())
W = list(map(int, input().split()))
# sub[S]: 集合S(二進数表記)をひとつの集合としたときの、(重さの総和 - 平均) ** 2
# 先に集合Sの重さの総和を計算してから変換することでO(2^N)
has_bit = lambda S, x: S >> x & 1
sub = [0] * (1 << N)
bitcnt = [0] * (1 << N)
for i in range(N):
for S in range(1 << i):
sub[S | 1 << i] = sub[S] + W[i]
bitcnt[S | 1 << i] = bitcnt[S] + 1
ave = sub[-1] / D
for S in range(1 << N):
sub[S] = (sub[S] - ave) ** 2
# DP[S]: d袋採用後の残りが集合Sとなるときの、Σ(xi - ave) ** 2 の最小値
# ただし、d袋採用時点で{N-d, N-d+1, ... , N-1} は必ず採用済でないといけない。
DP = [(1 << 62) - 1.0 for _ in range(1 << N)]
DP[-1] = 0 # 初期状態では全部残っている
# d袋目を入れる
for d in range(1, D + 1):
for S in range(1 << (N - d)): # 残る要素
DP[S] = (1 << 62) - 1.0 # ひとつも採用しなかった遷移を潰しておく
if bitcnt[S] < D - d: continue
bit_mask = ((1 << (N - d + 1)) - 1) & ~S
T = bit_mask # 今回採用する要素
while T > 0:
T = T & bit_mask
DP[S] = min(DP[S], DP[S + T] + sub[T])
T -= 1
# 答えを出力
print(DP[0] / D)