1. 程式人生 > >藍橋杯 最大的算式——動態規劃

藍橋杯 最大的算式——動態規劃

問題描述  題目很簡單,給出N個數字,不改變它們的相對位置,在中間加入K個乘號和N-K-1個加號,(括號隨便加)使最終結果儘量大。因為乘號和加號一共就是N-1個了,所以恰好每兩個相鄰數字之間都有一個符號。例如:
  N=5,K=2,5個數字分別為1、2、3、4、5,可以加成:
  1*2*(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

  本題採用動態規劃演算法,不要考慮括號,只從乘號來考慮,設dp[i][j]表示,i個元素裡有j個乘號時算式的最大值。sum[i]表示前i個元素的和。

   因此動態規劃狀態轉移方程為:dp[i][j]=max(dp[i][j],dp[l-1][j-1]*(sum[i]-sum[l-1]]),思路:假設最後一個乘號出現在第L個元素之前,所以問題就轉化為了求前L-1個數加j-1個乘號最大的算式值載乘上第L個元素到第i個元素的和,而L-1個元素加j-1個乘號又可以按相同的方法分解為更小的子問題。只要找出一個l使得最後一個乘號出現在這個位置上時的值最大,就可以存入dp[i][j]中。

#include<iostream>
#include<algorithm>

using namespace std;

long long dp[18][18],sum[18]={0};//因為題目沒說資料規模所以最好用long long

int main()
{
	int n,k,tmp;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>tmp;
		sum[i]=sum[i-1]+tmp; //將前i個元素的和一次存入陣列sum[]中
		dp[i][0]=sum[i];//初始化,乘號個數為0時,算式最大值就是前i個元素的和
	}
	for(int i=2;i<=n;i++)//自頂向下計算i個元素的算式最大值,注意從2開始元素最少有2個
	{
		tmp=min(i-1,k);//約束前i個元素最多有n-1個乘號,但乘號個數不能超過k
		for(int j=1;j<=tmp;j++)//乘號的個數
			for(int l=2;l<=i;l++)//最後一個乘號的位置,注意從2開始
				dp[i][j]=max(dp[i][j],dp[l-1][j-1]*(sum[i]-sum[l-1]));
	}
	cout<<dp[n][k]<<endl;
	return 0;
}