最大K乘积问题


①问题描述

设I 是一个n 位十进制整数。如果将I 划分为k 段,则可得到k 个整数。这k 个整数的乘积称为I 的一个k 乘积。

对于给定的I 、n和k,试设计一个算法,编程计算I 的最大k 乘积。

②编程任务

对于给定的I 、n和k,试设计一个算法,编程计算I 的最大k 乘积。

③样例输入文件示例                         输出文件示例

Intput                               output

2 1                                  15

15

二、解题思路:

4、实验方法步骤及注意事项:

①实验步骤:

找出最优解的性质,并刻画其结构特征

递归地定义最优值

以自底向上的方式计算出最优值

根据计算最优值时得到的信息,构造最优解

②解题思路

1)   首先用反证法证明最大k乘积问题具有最优子结构性质。

假设n位十进制整数I的最大k乘积记为f(n,k),前k-1段总共是m位,且1<=m<n,则最后一段为n-m位,用I(m,n-m)表示从第m位开始的最后n-m位十进制数,则f(n,k)=f(m,k-1)*I(m,n-m).现在我们假设前面m位十进制整数的最大k-1乘积不是f(m,k-1),而是e(m,k-1),则有e(m,k-1)>f(m,k-1), 左右两边同时乘以I(m,n-m)得e(m,k-1)*I(m,n-m)>f(m,k-1)*I(m,n-m)=f(n,k) 即f(n,k)不是I的最大K乘积与最初的假设相矛盾。所以f(m,k-1)是前面m位十进制整数的最大k-1乘积,即最大k乘积问题具有最优子结构性质。

2)   列出计算最优值的递归式,并以n=4,k=3,I=3456为例,在草稿纸上求出最优值。回答问题:何为最大k乘积问题的最优解,何为最大k乘积问题的最优解?

答:最大K乘积问题的最优解指的是解最大K乘积问题的一种方案,即是如何对n进行K段划分,最优值指的是在最优解的情况下得到最大K乘积的一个结果

3)   给出使用动态规划法计算最优值的算法,用C++语言描述

4)最大k乘积问题是要求出最优值还是最优解

最大K乘积问题是要求出最优值


代码思路:

区间DP 


设m(h,k) 表示: 从第h位到第K位所组成的十进制数
设dp(i,j)表示前i位(1-i)分成j段所得的最大乘积,
a数组储存给定的n个数字 ; 
则可得到如下经典的DP方程:
如果只分成一段,那么m[i][1]=w[1][i];
否则: 
 前i位(1:i)数字分j组乘积的最大值等于分为j-1组的结果再乘以一个因子

tips:预处理连续数字乘积和存放在m数组,dp[i][j]代表前i位有j个乘号。
dp[i][j]=max(dp[i][j],dp[k][j-1]*m[k+1][i]);    1<=k<i;

 

#include<iostream>  
#include<cstring>  
  
using namespace std;  
  
int n,k;  
int a[44];  
int dp[44][10];//前i个数中间有j个乘号   
int m[44][44];  
string s;  
void init()  
{  
    for(int i=1;i<=n;i++)m[i][i]=a[i];  
    for(int i=1;i<=n;i++)  
    {  
        for(int j=i+1;j<=n;j++)  
        {  
            m[i][j]=m[i][j-1]*10+m[j][j];  
        }  
    }  
 }   
int main()  
{  
    cin>>n>>k;  
    for(int i=1;i<=n;i++)  
    {  
        char ch;cin>>ch;  
        a[i]=ch-'0';  
    }  
    init();  
      
    for(int i=1;i<=n;i++)//枚举前i个数字   
    {  
        for(int j=0;j<i;j++)//枚举乘号个数  
        {  
            if(j==0)  
            {  
                dp[i][j]=m[1][i];continue;    
            }  
            for(int k=1;k<i;k++)//枚举乘号位置   
            {  
                dp[i][j]=max(dp[i][j],dp[k][j-1]*m[k+1][i]);  
            }  
              
        }  
    }  
    cout<<dp[n][k-1]<<endl;  //前n个数字分成n段,相当于前面添加n-1个乘号
    return 0;  
}  

  • 27
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值