P1018 [NOIP2000 提高组] 乘积最大 线性dp/记忆化搜索

P1018 [NOIP2000 提高组] 乘积最大 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这题输入数据很小,但是结果很大需要高精度,就用Python写了 。

第一种解法,就算将前i个元素分配j个乘号的最大乘积作为子状态。

n, k = map(int, input().split())
nn = str(n)
s = '1' + input()
dp = [[0] * 50 for _ in range(50)]
def dfs(f, cnt):
    if dp[f][cnt] != 0: return dp[f][cnt]
    tem = int(s[1:f + 1])
    if cnt == 0:#边界条件
        dp[f][cnt] = tem
        return tem
    res = 0
    for j in range(cnt + 1, f):#cnt个乘号最少需要cnt+1个元素
        res = max(res, dfs(j, cnt - 1) * int(s[j + 1:f + 1]))
    dp[f][cnt] = res
    return res

print(dfs(n, k))

第二种解法比较自然,将l-r区间的元素分配cnt个乘号作为一个子问题。类似于区间dp,但是多一步乘号数量的限制。多加一层循环枚举每个区间分配多少个乘号即可。

n, k = map(int, input().split())
nn = str(n)
s = '1' + input()
dp = [[[0] * 50 for _ in range(50)] for _ in range(50)]
def dfs(l,r, cnt):#l-r需要分配cnt个乘号
    if dp[l][r][cnt] != 0: return dp[l][r][cnt]
    tem = int(s[l:r + 1])
    if cnt==0 or l==r:#边界条件
        dp[l][r][cnt]=tem
        return tem
    res=0
    for k in range(l,r):#枚举区间分配
        for num in range(0,cnt+1):#分配给左区间的乘号
            if k-l<num:
                break
            res=max(res,dfs(l,k,num)*dfs(k+1,r,cnt-num))
    dp[l][r][cnt]=res
    return res
print(dfs(1,n, k))

和区间dp很像,可以和石子合并问题比对一下。

int dfs(int l, int r) {//合并l-r的消耗
	if (dp[l][r])return dp[l][r];
	if (l >= r)return 0;//边界条件,合并自己0消耗
	int res = 0;
	rep(k, l, r-1) {//枚举分割区间
		res = max(res, dfs(l, k) + dfs(k + 1, r) + arr[r] - arr[l - 1]);
	}
	return dp[l][r] = res;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值