乘积最大

题目链接:http://wikioi.com/problem/1017/

分析部分采摘参考题解网址:http://wikioi.com/solution/list/1017/

分析如下: 
    设字符串长度为n,乘号数为k,如果n=50,k=1时, 
有(n-1)=49种不同的乘法,当k=2时,有C(2,50-1)=1176种乘法,既C(k,n-1)种乘法,当n、k稍微大一些的时候,用穷举的方法就不行了。 
设数字字符串为a1a2…an 
K=1时:一个乘号可以插在a1a2…an中的n-1个位置,这样就得到n-1个子串的乘积: 
    a1*a2…an, a1a2*a3…an, …, a1a2…a n-1*an (这相当于是穷举的方法) 
    此时的最大值=max{a1*a2…an, a1a2*a3…an, … , a1a2…a n-1*an } 
  K=2时,二个乘号可以插在a1a2…an中n-1个位置的任两个地方, 把这些乘积 
   分个类,便于观察规律: 
     ①倒数第一个数作为被乘数: 
     a1*a2 …a n-3 a n-2 a n-1*an, 
     a1a2 …*a n-2 a n-1*an, 
     a1a2 …*a n-1*an。 
    设符号F[n-1,1]为在前n-1个数中插入一个乘号的最大值,则的最大值为 
     F[n-1,1]*an。 
    ②倒数第二个数作为被乘数: 
    a1*a2 …an-3 a n-2* a n-1, 
    an … a1a2 …*a n-2*a n-1an, 
    a1a2…*a n-3 a n-2* a n-1 an。 
    设符号F[n-2,1]为在前n-2个数中插入一个乘号的最大值,则的最大值为 
      F[n-2,1]*a n-1 an 
    ③倒数第三个数作为被乘数: 
         … 
     设符号F[n-3,1]为在前n-3个数中插入一个乘号的最大值,则的最大值为 
     F[n-3,1]*a n-2 a n-1 an 
          …… 
      a3~an作为被乘数:F[2,1]*a3 …a n-2 a n-1 an 
     此时的最大乘积为: 
       F[n,k]=max{F[n-1]*an,F[n-2,1]*a n-1 an, 
            F[n-3,1]*a n-2 a n-1 an, 
            F[2,1]*a3 …a n-2 a n-1 an} 
     设F[i,j]表示在 i 个数中插入 j 个乘号的最大值,g[i,j]表示从ai到aj的数字列,则可得到动态转移方程: 
     F[i,j] = max{F[i-1,j-1]*g[i,i], F[i-2,j-1]*g[i-1,i], 
           F[i-3,j-1]*g[i-2,i], …., F[j,j-1]*g[j+1,i]} 
           (1<=i<=n, 1<=j<=k) 
   边界: F[i,0] =g[1,i] (数列本身) 
    阶段:子问题是在子串中插入j-1,j-2……1,0个乘号,因此乘号个数作为阶段的划分(j个阶段) 
    状态:每个阶段随着被乘数数列的变化划分状态。 
    决策:在每个阶段的每种状态中做出决策。 
动态规划: 
  for(i=1;i<=n;i++)/*方程:f[i,j]表示前i个数中插入j个*号的最优值。*/ 
    for(j=1;j<=i+1;j++) 
     for(l=1;l<=i-1;l++) 
      f[i][j]=max(f[i][j],f[l][j-1]*g[l+1][i]); 
输出f[n][k]

-------------------------------------------------------------------------------------------华丽分割线--------------------------------------------------------------------------------------------

以下为自己写的代码:

#include<stdio.h>
int dp[51][51],a[51][51];
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int n,k,i,j,t;
char s[51];
scanf("%d%d",&n,&k);
scanf("%s",s);
for(i=0;i<n;i++)
{
t=0;
for(j=i;j<n;j++)
{
t=t*10+s[j]-'0';
a[i][j]=t;
}
}
for(i=0;i<n;i++)
dp[i][0]=a[0][i];

//阶段:子问题是在子串中插入k-1,k-2……1,0个乘号,因此乘号个数作为阶段的划分(k个阶段) 
// 状态:每个阶段随着被乘数数列的变化划分状态。 
// 决策:在每个阶段的每种状态中做出决策。 
for(i=0;i<n;i++)
for(j=1;j<=k;j++)
for(t=0;t<i;t++)
{
dp[i][j]=max(dp[i][j],dp[t][j-1]*a[t+1][i]);
}
printf("%d\n",dp[n-1][k]);
return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林下的码路

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

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

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

打赏作者

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

抵扣说明:

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

余额充值