动态规划-Hard题目

2 篇文章 0 订阅

动态规划

题目一: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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值