美团--合并金币
美團–合并金幣
文章目錄
- 美團--合并金幣
- 一、題目描述
- 二、分析
- 三、代碼
一、題目描述
同樣還是兩道一樣的題!!!
二、分析
- 拿到題目,看到相鄰兩字,就考慮動態規劃問題。
- 這里第一步確定dp[i][j]是什么意思,我這里規定dp[i][j]就是從第i個位置開始到第j個位置結束,這一堆合并金幣所需的最小成本。
- 第二步 確定狀態轉移方程
打個比方說如果輸入4個數 2 3 6 1(為了方便理解,我把下標定為從1開始 到4結束)
那我們就先比方說dp[1,3]也就是從第一個位置到第三個位置結束,那也就是2 3 6的最小成本數,我們有兩種情況:
從2到3 是一堆,然后6是一堆;
2是一堆,3 到6是一堆。
那么我們這個dp[1][3]的公式就是dp[1][2]+dp[3][3]+2+3+6或dp[1,1]+dp[2][3]+2+3+6;
后面的2+3+6的意思是最后一次的成本數,也就是不管你是從哪個開始到哪個結束,最后一次的成本永遠是從開始到結束的總和。
比如說如果是從2 3為一堆先開始,那就是2 3 6=>5 6(5)=>11(5+11) 括號里是成本數。
- 那我們現在可以確定dp[i][j]的公式就是設置一個變量k;i<=k<j,dp[i][j]=dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j] + lastMoney); 這個k是放在循環里的。
- 接下來就是具體怎么放到代碼當中了
- 既然讓我求解在一個區間上的最優解,那么我把這個區間分割成一個個小區間,求解每個小區間的最優解,再合并小區間得到大區間即可。
- 所以在代碼實現上,我可以枚舉區間長度len為每次分割成的小區間長度(由短到長不斷合并),內層枚舉該長度下可以的起點,自然終點也就明了了。
- 然后在這個起點終點之間枚舉分割點,求解這段小區間在某個分割點下的最優解。
- 第三部 給出base case
- 因為還沒合并,花費當然為0嘍
三、代碼
#include<bits/stdc++.h> using namespace std;const int maxn = 105; int n; int num[maxn]={0}; int dp[maxn][maxn]={0}; int cost[maxn][maxn]={0};int main() {cin>>n;for(int i = 1;i <= n;i++) cin>>num[i];memset(dp,0x3f,sizeof(dp));//花費初始化for(int i = 1; i <= n;i++){for(int j = i; j <= n ;j++){for(int k = i; k <= j; k++){cost[i][j] += num[k];}}}//base casefor(int i = 1; i <= n ;i++) dp[i][i] = 0;//枚舉每個小區間,小區間的長度為lenfor(int len = 2; len <= n;len++){//小區間的起始位置for(int l = 1; l <= n - len + 1 ;l++){//小區間的結束位置int r = l + len - 1;//枚舉該區間內的最優解for(int k = l ; k < r; k++){dp[l][r] = min(dp[l][r],dp[l][k] + dp[k + 1][r] + cost[l][r]);}}}cout<<dp[1][n]<<endl;return 0; }總結
- 上一篇: 美团/力扣(647)--回文字串
- 下一篇: 美团--最小唯一前缀