「题解」乘积最大

题目描述

 输入一个长度为N的数字串, 用K个乘号将它分为 (K+1) 个部分,使得得到的乘积最大
 例如N = 3 , K = 1,输入的数字串为 312
 分法有两种
 312 = 36
 31
2 = 62
 最大值为62

输入格式

 输入共两行
 第一行,正整数 N 和 K
 第二行,一个数字串

输出格式

 用K个乘号将数字串划分为(K+1)个部分所得到的最大乘积

样例

样例输入1

3 1
312

样例输出1

62

样例输入2

7 3
3314245

样例输出2

278040

数据范围与提示

2 <= N <= 30
1 <= K <= 10

分析

 定义f[l,r]表示区间l~r的乘积最大值肯定不合适,因为这样做没有合适的方法判断有多少乘号,所以我们只能定义f[i,l,r]表示将i个乘号插入区间[l,r]的最大乘积,但是这样做时间复杂度太高了,我们定义f[i,j]表示将i个乘号插入前j个数中的最大乘积,s[i,j]表示第i到j位所形成的数
 我们发现f[3,n]=max(f[2,n-1]*s[n,n],f[2,n-2]*s[n-1,n],…f[2,4]*s[5,n],f[2,3]*s[4,n])而f[2,n-1]=max(f[1,n-2]*s[n-1,n-1],f[1,n-3]*s[n-2,n-1]…f[1,3]*s[4,n-1],f[1,2]*s[3,n-1])
 以此类推,我们可以看到f[i,j]已经具有了最优子结构的特征,可以用动态规划求解

 初始化:f[0,j]=s[1,j]
 状态转移方程:f[i,j]=max(f[i,j],f[i-1,k]*s[k+1,j])[k=i~j-1]
 目标:f[k,n]

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int M = 35;
int n, k;
int a[M];
long long f[M][M];

long long get(int st, int ed) { //即s[i,j]
	long long num = 0;
	for(int i = st; i <= ed; i ++) {
		num = num * 10 + a[i];
	}
	return num;
}

void Read(int len) {
	char x = getchar();
	while(x < '0' || x > '9') x = getchar();
	for(int i = 1; i <= len; i ++) {
		a[i] = (x - '0');
		x = getchar();
	}
} 

int main() {
	scanf("%d %d", &n, &k);
	Read(n);
	for(int i = 1; i <= n; i ++) {
		f[0][i] = get(1, i);
	}
	for(int i = 1; i <= k; i ++) {
		for(int j = i + 1; j <= n; j ++) {
			for(int q = i; q < j; q ++) {
				f[i][j] = max(f[i][j], f[i - 1][q] * get(q + 1, j));
			}
		}
	}
	printf("%lld", f[k][n]);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/yu_______chen/article/details/107450237