乘积最大【DP】(非高精版)

【题目描述】
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:

设有一个长度为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≤10,1≤K≤6)

第二行是一个长度为N的数字串。

【输出】
输出所求得的最大乘积(一个自然数)。

【输入样例】
4 2
1231
【输出样例】
62

分析:这里我们看到题目给出了两个变量:n和k。按照一般套路,我们要输出的答案是f【n】【k】。想一下,n和k各自表示什么?相信读者很快就明白了:f【n】【k】表示前n个数插入k个符号可以得到的最大值,a【i】【j】表示数字串中i-j表示的数字。接下来我们就可以考虑方程如何写了。f【i】【j】是通过是通过什么状态来得到的呢?答案是max(f【o】【j-1】*a【o+1】【i】)。我们想一下我们是如何得到这个方程的。前i个数插入j个乘号可以得到的最大值?那么我们先假设j-1个乘号都已经插入好了,接下来只需要考虑剩下的这一个符号插在哪里,和剩下的数组成乘机最大即可。还有一些具体细节要看一下代码。如果发现哪里有错误可以留言评论,我看到后第一时间订正。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
using namespace std;
long long f[11][7],a[11][11];
char s[11];
inline long long zhuanhuan(int x,int y)//储存x-y表示的数 
{
    long long ans=s[x-1]-48;
    for(int i=x;i<y;i++)
    {
        ans=ans*10+s[i]-48;
    }
    return ans;
}
inline long long _max(long long a,long long b)
{
    if(a>b) return a;
    else return b;
}
int main()
{
    int n,k,j,o;
    long long sum,ans=0;
    scanf("%d%d",&n,&k);
    scanf("%s",s);
    int l=strlen(s),i;//这里的l多余了,可以换成n 
    for(i=1;i<=l;i++)
    {
        for(j=i;j<=l;j++)
        {
            a[i][j]=zhuanhuan(i,j);//初始化a数组 
        }
    }
    for(i=1;i<=l;i++)
    {
        f[i][0]=a[1][i];//dp数组初始化 
    }
    for(i=1;i<=k;i++)//为什么要先枚举乘号的个数?方便接下来j和o数组的初始化 
    {
        for(j=i+1;j<=l;j++)//要插入i个乘号,那么至少要有i+1个数字才可以 
        {
            sum=0;
            for(o=i;o<j;o++)//要插入i-1个乘号,那么至少要有i-1+1个数字才可以 
            {
                sum=_max(sum,f[o][i-1]*a[o+1][j]);
            }
            f[j][i]=sum;//储存 
        }
    }
    printf("%lld",f[n][k]);//输出答案 
    return 0;
}

谢谢大家

posted @ 2018-03-13 21:15  最爱丁珰  阅读(39)  评论(0编辑  收藏  举报