最大K乘积问题
问题描述
设I是一个n位十进制整数。如果将I划分为k段,则可得到k个整数。这k个整数的乘积称为I的一个k乘积。试设计一个算法,对于给定的I和k,求出I的最大k乘积。
(没读懂)
自己解析:
n位十进制整数(例如:4位整数1234)分成k段(例如分成三段,有三种情况)
三种情况:
1,2,34 | 1,23,4 | 12,3,4 |
---|
问题是这几种情况哪种能使乘积最大,最大乘积是多少?
输入n(整数的位数),x为分成几段,I为那个整数
例如:4 3 1234
可以看到4位整数分成3段的问题可以等价于这三种情况取最大值,这三种情况的详细描述见下图
把这三种情况拿出来接着分:
规律就是i位整数划分为k段的最大乘积=max{i-1位整数划分为k-1段的最大乘积×}
代码:
#include<iostream>
#include<cstring>
using namespace std;
int n,k,x;
int a[44];//存储输入的所有数字
int dp[44][10];//状态矩阵
int m[44][44];
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>>x;//n表示共几位数,k表示分几段
for(int i=1;i<=n;i++)
{
char ch;
cin>>ch;
a[i]=ch-'0';//字符转整数,把所有数字都录入a[]数组中
}
init();
for(int i=1;i<=n;i++)//构造状态数组
{
for(int j=1;j<=i;j++)
{
if(j==1)//前n位分成1段时的最大乘积,也是dp数组的第一列
{
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][x]<<endl; //前n个数字分成n段,相当于前面添加n-1个乘号
return 0;
}
init()函数构造出的二维数组m
dp数组的构造
举个例子:dp数组中36是如何得来的:
之前的解析是 3位整数123划分成2段的最大值等价于max{2位整数12分成1段×3,1位整数1分成1段×23}
我们来看一下循环中当走到i=3,j=2这一步时到第三层循环是什么情况:
dp[i][j]=max(dp[i][j],dp[k][j-1]*m[k+1][i])
i=3,j=2,k=1时
dp[3][2]=max(dp[3][2],dp[1][1]*m[2][3]);
即dp[3][2]=max(0,1×23)=23
i=3,j=2,k=2时
dp[3][2]=max(dp[3][2],dp[2][1]*m[3][3]);
即dp[3][2]=max(23,12×3)=36
1×23和12×3的比较大小正好对应了max{2位整数12分成1段×3,1位整数1分成1段×23}。