问题描述:输入n和k,其中n为十进制数长度,k为分的段数,然后输入一个长度为n的十进制数,算出分成k段之后最大的乘积
例:输入1234
有以下结果 1x2x34=68,1x23x4=92,12x3x4=144,最大乘积为144
我们利用MaxI[n][k]表示长度为n的最大k乘积,用I(s,t)表示从s开始到t的十进制数,当我们的k=1时(即只分成一段)最大值就是本身即I(1,n);如果k>1,则我们的最大值就是前d的个数分成k-1的最大值乘以剩下的十进制数,即MaxI[n][k]=max{MaxI[d][k-1]*I(d+1,n)};
然后我们可以使用动态规划来解决问题
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#define MAXN 50
#define MAXK 10
//设置静态变量
static int m[MAXN][MAXN];//m[i][j]表示前i个数的j乘积
static int w[MAXN][MAXN];//w[i][j]表示从i到j的十进制数
void MaxDp(int *a,int n,int k)
{
int i,j,d;
int max,temp;
//初始化m数组
for(i=1;i<=n;i++)
m[i][1]=w[1][i];
//动态规划求值
/*
因为求的是m[n][k]的最大值
所以第一个for循环用来控制行数n
*/
for(i=1;i<=n;i++)
{
//第二个for循环用于控制列数k
//由于第一列已经初始化,从j=2开始
for(j=2;j<=k;j++)
{
max=0;
//第三个for循环用于动态规划,通过m[n][k]=m[d][k-1]+w[d+1][i]来求值
for(d=1;d<i;d++)
{
if((temp=m[d][j-1]*w[d+1][i])>max)
{
max=temp;
}
m[i][j]=max;
printf("\nm[%d][%d]*w[%d][%d]=%d\n",d,j-1,d+1,i,max);
// printf("%d\t",m[i][j]);
}
}
printf("\n");
}
printf("\n\n\n");
for(i=1 ; i<= n; i++)
{
for(j=1 ; j<= n; j++)
printf("%5d",m[i][j]);
printf("\n");
}
// return max;
}
void main()
{
int n,k,i,j;
int a[MAXN]={0},len=0;
char c ;
printf("请输入长度和段数:");
scanf("%d %d",&n,&k);
fflush(stdin);
printf("请输入长度为%d的十进制数:\n",n);
//scanf("%s",a);
while((c=getchar())!='\n')
{
a[++len]=c-'0';//将字符转换成整形
}
//初始化w二维数组
for(i=1;i<=n;i++)
{
w[i][i]=a[i];
for(j=i+1;j<=n;j++)
{
w[i][j]=w[i][j-1]*10+a[j];
}
}
printf("w数组初始化后为:\n");
for(i=1 ; i<= n; i++)
{
for(j=1 ; j<= n; j++)
printf("%5d",w[i][j]);
printf("\n");
}
MaxDp(a,n,k);
printf("最大%d乘积为:%d\n",k,m[n][k]);
}
其中使用动态规划求解的核心代码为
for(i=1;i<=n;i++)
{
for(j=2;j<=k;j++)
{
max=0;
for(d=1;d<i;d++)
{
if((temp=m[d][j-1]*w[d+1][i])>max)
{
max=temp;
}
m[i][j]=max;
printf("\nm[%d][%d]*w[%d][%d]=%d\n",d,j-1,d+1,i,max);
// printf("%d\t",m[i][j]);
}
最后得到的m[n][k]即为我们的最大k乘积的值