算法训练 乘积最大
时间限制:1.0s 内存限制:256.0MB
锦囊1
动态规划。
问题描述
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312, 当N=3,K=1时会有以下两种分法:
312=36
312=62
这时,符合题目要求的结果是:31*2=62
现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
输入格式
程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。
输出格式
输出所求得的最大乘积(一个自然数)。
样例输入
4 2
1231
样例输出
62
思路1:
dp[N] [K]字符串前N位插入K个乘号后所能得到的最大值
例如312:当N=3, K=1时,从N=1, K=0开始推导
dp[1] [0] = 3
dp[2] [0] = 31
dp[3] [1] = max(0 , dp[1,0] * 12) = max(0,36) = 36
dp[3] [1] = max(36 , dp[2,0] * 2) = 62
例如1231:当N = 4,K = 2时,从N = 1 ,K = 0开始推导
dp[1] [0]:1
dp[2] [0]:12
dp[3] [0]:123
dp[4] [0]:1231
dp[2] [1]:max(0 , dp[1] [0] * 2) = 2;
dp[3] [1]:max(2 , dp[1] [0] * 23) = 23;
dp[3] [1]:max(23,dp[2] [0] * 3) = 36;
dp[3] [2]:max(0,dp[1] [1] * 23) = 0;
dp[3] [2]:max(0,dp[2] [1] * 3) = 6;
dp[4] [1]:max(0,dp[1][0] * 231) = 231;
dp[4] [1]:max(231,dp[2] [0] * 31) = 372;
dp[4] [1]:max(372,dp[3] [0] * 1) = 372;
dp[4] [2]:max(0,dp[1] [1] * 231) = 0;
dp[4] [2]:max(0,dp[2] [1] * 31) = 62;
dp[4] [2]:max(62,dp[3] [1] * 1) = 62;
动态规划方程: dp[i][j] = max(dp[i][j],dp[k][j-1] * get(k + 1,i));
#include<iostream>
using namespace std;
int n,k;
int a[100];
int dp[100][100];
int get(int x,int y)//用来取出某个符号后面的数字,取的是下标x到y之间的数字组成的数值
{
int sum = 0;
for(int i = x;i <= y;i ++)
sum = sum * 10 + a[i];
return sum;
}
void ok()
{
for(int i = 1;i <= n;i ++)
dp[i][0] = get(1,i);
for(int i = 2;i <= n;i ++)
for(int j = 1;j <= k && j < i ;j ++)
for(int k = 1;k < i ;k ++)
dp[i][j] = max(dp[i][j],dp[k][j-1] * get(k + 1,i));
//在前i个数中,有j个乘号
}
int main()
{
cin >> n >> k;
string s;
cin >> s;
for(int i = 0;i < s.size();i ++)
a[i + 1] = s[i] - '0';
ok();
cout << dp[n][k];
return 0;
}
思路2:利用暴力求解法:
例如312 N = 3, K = 1
分别列出
3,12
31,2
首先从第一个数开始,得到3 * 12 = 36;
然后一次类推,得到31 * 2 = 62;
每次推K个符号即可
例如1231 N = 4, K = 3
然后判断哪个是K个符号可以分开的,如果是的话,就累乘在一起,找出最大值即可
分别列出
1,2,23,231
12,3,31
123,1
1231
则可以分别得出
1,2,31;
1,23,1;
1,231 (不符合进入求解最大值的循环当中)
12,3,1;
123,1 (不符合进入求解最大值的循环当中)
1231 (不符合进入求解最大值的循环当中)
#include <iostream>
#include <algorithm>
using namespace std;
string a;
int n,k,maxs;
void bfs(int t,int s,int l)//t是乘号个数,s是用来乘的数
{
int xs = 0;
if(t == k)
{
for(int i = l;i < n;i++)//在l和n之间的数进行循环求最大值
xs = xs * 10 + a[i] - '0';
if(s * xs > maxs)//将传进来的s跟后面的值相乘
maxs = s * xs;
return ;
}
for(int i = l;i < n;i++)//l-n,依次得到乘法的成员
{
xs = xs * 10 + a[i] - '0';
bfs(t + 1,s * xs,i + 1);
}
}
int main()
{
cin >> n >> k;
cin >> a;
maxs = 0;
bfs(0,1,0);
cout << maxs << endl;
}