题目链接: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;
}