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

首先有一個猜想,由a*(b+c)*d>a*b+c*d,猜想任意一個序列,連加優先計算,所得結果最大,我們只需要在這些加號優先計算的序列中尋找答案就可以了。

是否適合使用動態規劃

(1)滿足最優子結構

子問題 求下標從x到結束的序列,新增符號以後得到的最大值,記為f(x)

另外,下標從x到y犯人序列,連加得到的和記為g(x,y)子問題

那麼,f(x)=max{g(top,i-1)*f(i)}

其中,i表示序列(下標從top到N-1)第一個乘號後的數的下標,取遍top+1到N-1

2)滿足重疊子問題

大量f(i)需要重複計算

具體操作注意答案數值巨大,用long long;乘號數量限制,加上可使用乘號數量這個引數

#include<stdio.h>
int a[100],c[100]={0};
int N,K;
long long b[100][100]={0};
long long g(int top,int end){
int i;
long long q=0;
for(i=top;i<=end;i++)
    q+=a[i];
return q;
}
long long f(int begin,int k){
int i;
long long t,ans=0;
if(b[begin][k])return b[begin][k];
if(k==0)
    return g(begin,N-1);
if(begin==N-1&&k)
    return 0;
for(i=begin+1;i<=N-1;i++){
    if(ans<(t=(g(begin,i-1)*f(i,k-1)))){
        ans=t;
    }
}
return b[begin][k]=ans;
}
int main(){
int i;
scanf("%d%d",&N,&K);
for(i=0;i<N;i++){
    scanf("%d",&a[i]);
}
printf("%lld\n",f(0,K));
return 0;
}