算法訓練 最大的算式 DP


算法訓練 最大的算式  
時間限制:1.0s   內存限制:256.0MB
   
問題描述
  題目很簡單,給出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處理,就往這邊想了,先確定了dp[i][j]表示前i個數中使用了j個乘號的所得到最大值。

糾結於插入的位置,所以只好再設一重循環,表示可以插入的位置,范圍從2到n。

動態轉移方程是根據01背包的思想轉化得來的,選定插入位置,前面的最大值乘后邊從插入位置到i之前的總和,原來想的是只乘一個數,但是一起乘總比一個去乘要大。

所以狀態轉移方程:dp[i][j]=max(dp[i][j],dp[p-1][j-1]*(p到i之間的總和));

最后就是初始狀態的考慮,dp[i][0]表示沒有用到乘號,所以dop[i][0]就是前i項的和。


代碼:

#include<iostream>
#include<algorithm>
using namespace std;
long long dp[16][16];
long long ans[16];
void init(int n,int k)
{
    long long num;
    long long sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&num);
        ans[i]=num;
        sum+=num;
        dp[i][0]=sum;//在沒有使用乘號的情況全部使用加法
    }
}
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    init(n,k);
    for(int i=1;i<=n;i++)//n個數
    {
        for(int j=1;j<=i-1;j++)//最多有i-1個乘號,數量級較小,就不剪枝了
        {
            for(int p=2;p<=i;p++)//第j個乘號插入的位置,如果和前面的乘號位置重疊了,也不影響,還是原來的dp[i][j]
            {
                dp[i][j]=max(dp[i][j],dp[p-1][j-1]*(dp[i][0]-dp[p-1][0]));//從車如位置到i的和,一起乘總比一個乘要大
            }
        }
    }
    printf("%lld\n",dp[n][k]);
    return 0;
}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM