乘积最大(dp)

链接:https://ac.nowcoder.com/acm/contest/1071/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312, 当N=3,K=1时会有以下两种分法:

  1. 3*12=36
  2. 312=62
    这时,符合题目要求的结果是:31
    2=62
    现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
    输入描述:
    第一行共有2个自然数N,K(6 ≤ N ≤ 40,1 ≤ K ≤ 6)
    第二行是一个长度为N的数字串。
    输出描述:
    输出所求得的最大乘积(一个自然数)。
    示例1
    输入
    复制
4 2
1231

输出
复制

62

/*
当时团队赛时,感觉要大数计算就为了省事就用python写的,
现在补一份C++代码。
字符串s下标从1开始,
dp[i][j]:表示 s[i]前 放j个 乘号,
那么有状态转移方程:

dp[i][j] = max(dp[i][j],dp[k][j-1]*num[k+1][i])
j<= k < i,( k>=j:  j-1个乘号至少有j位 )

*/

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
char s[50];
LL num[50][50],dp[50][10];
void init(int n)
{
    for(int i = 1; i <= n; i++)
    {
        for(int j = i; j <= n; j++)
        {
            num[i][j] = num[i][j-1] * 10 + (s[j]-'0');
        }
    }
}
int main()
{
    int n,k;
    scanf("%d%d%s",&n,&k,s+1);
    init(n);
    for(int i = 1; i <= n; i++)
    {
        dp[i][0] = num[1][i];
        for(int j = 1; j <= n; j++)
        {
            for(int k = j; k < i; k++)
            {
                dp[i][j] = max(dp[i][j],dp[k][j-1]*num[k+1][i]);
            }
        }
    }
    printf("%lld\n",dp[n][k]);
    return 0;
}

用python只要爆搜就好:

vis = [False for x in range(n)]
mp = []
ans = 0
def dfs(st,n,m,cnt,res):
    global ans
    if(n-st-1 < m-cnt):
        return
    if(cnt == m):
        tm = res
        res *= mp[st][n-1]
        if res > ans:
            ans = res
        res = tm
        return
    for i in range(st,n):
        if(vis[i]==False):
            vis[i] = True
            #print(mp[st][i])
            dfs(i+1,n,m,cnt+1,res*mp[st][i])
            vis[i] = False
n,m = map(int,input().split())
s = input()
tmp = 0
for i in range(n):
    my_list = []
    tmp = 0
    for j in range(n):
        if j < i:
            my_list.insert(j,0)
            continue
        tmp = tmp * 10 + int(s[j])
        my_list.insert(j,tmp)
    mp.insert(i,my_list)
#print(mp)
dfs(0,n,m,0,1)
print(ans)
### 关于洛谷平台上的区间动态规划乘积问题 #### 解析与实现 对于洛谷平台上涉及区间动态规划(DP)并处理乘积问题的任务,可以考虑如下解析方法: 在解决此类问题时,通常定义 `f(i, j)` 表示从前 `i` 个数字中插入 `j` 个乘号所能得到的最大乘积[^1]。初始条件设定为当不插入任何乘号 (`j = 0`) 的情况下,`f(i, 0)` 应等于由第 `1` 至第 `i` 数字组成的整数值;而如果尝试在一个长度不足以容纳所需乘号数量的情况下求解,则返回 `0`。 为了有效推进解决方案,在遍历过程中需维护一个三维数组来存储中间结果,其中第三维代表当前已使用的乘号数目。通过迭代更新这些值直到达到所需的乘号总数为止,最终可获得全局最优解。具体来说,状态转移方程表达式为: \[ f(i,j)=\max{\left(f(k,j-1)\times S[k+1]\cdots S[i]\right)} \] 此处 \(S[k+1]\cdots S[i]\) 是指从位置 `k + 1` 开始到 `i` 结束这一段连续子串所表示的整数[^2]。 ```python def max_product(n, s, k): # 初始化 DP table 和辅助变量 dp = [[0] * (k + 1) for _ in range(n)] # 设置基础情形下的值 for i in range(1, n + 1): num_str = int(s[:i]) dp[i - 1][0] = num_str # 动态规划填表过程 for cnt_mul in range(1, min(k, n - 1) + 1): # 控制乘号的数量 for end_pos in range(cnt_mul, n): # 当前考察序列结尾处索引 temp_max = float('-inf') for split_point in range(end_pos): product_part = int(s[split_point + 1 : end_pos + 1]) current_val = dp[split_point][cnt_mul - 1] * product_part if current_val > temp_max: temp_max = current_val dp[end_pos][cnt_mul] = temp_max return str(dp[-1][-1]) # 示例调用函数 n = 5 s = "9876" k = 2 print(max_product(n, s, k)) ``` 此代码片段实现了上述提到的状态转移逻辑,并针对给定输入参数进行了测试验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enco-Lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值