Openjudge-8782乘积最大(区间dp)

题目:

设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:

有一个数字串:312,当N=3,K=1时会有以下两种分法:

1)  3*12=36

2)  31*2=62

这时,符合题目要求的结果是:31*2=62

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。

输入程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。输出输出所求得的最大乘积(一个自然数)。(保证最终答案不超过int范围)

样例:

输入:

  4 2

  1231

输出:

  62

这是一道典型的区间dp

#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
    char a[47];
    int n, k, sav[45] = {};
    long long dp[45][10] = {}, dl[45][45] = {}, s;
    scanf("%d%d", &n, &k);
    scanf("%lld", &s);
    for(int i = n;i >= 1;i--)
    {
        dl[i][i] = s % 10;
        s /= 10;
    }
    for(int i = 2;i <= n;i++)
    {
        for(int j = i - 1;j >= 1;j--) dl[j][i] = dl[j][i - 1] * 10 + dl[i][i];
    }
    for(int i = 1;i <= n;i++)
    {
        dp[i][0] = dl[1][i];    
    }//初始化 
    for(int k1 = 1;k1 <= k;k1++)
    {
        for(int i = k1 + 1;i <= n;i++)
        {
            for(int j = k1;j < i;j++)
            {
                dp[i][k1] = max(dp[i][k1],dp[j][k1 - 1] * dl[j + 1][i]);    
            }
        }
    }
    printf("%d", dp[n][k]);
    return 0;    
}
//对于每一个区间,都有分段和不分段两种选择
//还要考虑整体分段次数不能超过k
//因此可以猜想需要枚举,分段点的位置,或者段的两端

ps:注释是自己的错误思路

正确思路是将要讨论的状态设为前i个数中,用了k1个乘号

即计算dp[i][k1]

posted @ 2021-04-16 16:04  Mint-hexagram  阅读(117)  评论(0编辑  收藏  举报