1. 程式人生 > >藍橋杯 演算法訓練 ALGO-116 最大的算式 動態規劃 資源分配型別(最大乘積)

藍橋杯 演算法訓練 ALGO-116 最大的算式 動態規劃 資源分配型別(最大乘積)

演算法訓練 最大的算式
時間限制:1.0s 記憶體限制:256.0MB
問題描述
  題目很簡單,給出N個數字,不改變它們的相對位置,在中間加入K個乘號和N-K-1個加號,(括號隨便加)使最終結果儘量大。因為乘號和加號一共就是N-1個了,所以恰好每兩個相鄰數字之間都有一個符號。例如:
  N=5,K=2,5個數字分別為1、2、3、4、5,可以加成:
  12(3+4+5)=24
  1*(2+3)(4+5)=45
  (1
2+3)*(4+5)=45
  ……
輸入格式
  輸入檔案共有二行,第一行為兩個有空格隔開的整數,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行為 N個用空格隔開的數字(每個數字在0到9之間)。
輸出格式
  輸出檔案僅一行包含一個整數,表示要求的最大的結果
樣例輸入
5 2
1 2 3 4 5
樣例輸出
120
樣例說明
  (1+2+3)4

5=120

分析:既然是動態規劃,就按照動態規劃的思路來就可以了,方法其實並不唯一。這裡我引用網上的一篇思路,個人感覺比我自己的要好。

思路:設 s u m [ i ]

sum[i] 為前 i i 個數的總和,那麼從 j j k
k
的總和為 s u m [ k ] s u m [ j 1 ] sum[k]-sum[j-1] 。設 d p [ i ] [ j ] dp[i][j] 表示前 i i 個數中有 j j 個乘號的最大的結果,則想要知道 d p [ i ] [ j ] dp[i][j] ,可以嘗試從第二個數的前面一直到最後一個數的前面依次新增乘號,將最大的結果儲存至 d p [ i ] [ j ] dp[i][j] 中。就可以得到狀態轉移方程為:
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ l 1 ] [ j 1 ] ( s u m [ i ] s u m [ l 1 ] ) ; dp[i][j]=max(dp[i][j],dp[l-1][j-1]*(sum[i]-sum[l-1]);
l l 為插入相乘的兩個數的後一個數字的座標。

注:本篇內容轉自https://blog.csdn.net/liuchuo/article/details/51990007

#include <iostream>
using namespace std;
#define max(a, b) a > b ? a : b;
long long dp[16][16];
int sum[16];

int main()
{
	int n, k;
	cin >> n >> k;
	for(int i = 1; i <= n; i++)
	{
		int temp;
		cin >> temp;
		sum[i] = sum[i-1] + temp;
		dp[i][0] = sum[i];
	}
	for(int i = 2; i <= n; i++)
	{
		for(int j = 1; j <= i-1 && j <= k; j++)
		{
			for(int l = 2; l <= n; l++)
			{
				dp[i][j] = max(dp[i][j], dp[l-1][j-1] * (sum[i] - sum[l-1]));
			}
		}
	}
	cout << dp[n][k];
	return 0;
}