區間dp練習題

題目鏈接:https://www.luogu.com.cn/problem/T121078?contestId=26815

題目描述

阿偉死了 qwq (終於死了) ,因爲這個他玩的遊戲實在是太難了,他通宵幾天都沒能過關,最後猝死在電腦前,但是他臨走前,給了一個任務,希望你能幫他通過這個遊戲,爲了阿偉能瞑目,你現在要開始繼續玩這個遊戲。

這個遊戲是這樣的,你有 n 個矩陣排成一個圈,假設第 i 個矩陣的行和列分別爲 a 和 b,那麼第 i+1 個矩陣的行和列 分別爲 b 和 c ,第 i-1 個矩陣的行和列分別爲 d 和 a ,意思是 相鄰兩個矩陣一定能進行一次矩陣乘法,下面成爲合併操作。

現在你要將矩陣進行合併操作,假設相鄰兩個矩陣的行和列分別爲 (p,q) ,(q,r) ,那他們進行一次合併操作,變成了一個 (p,r)的矩陣,這時候會產生一些金幣,金幣的數量爲 p * q * r 。

現在你需要進行多次上述的合併矩陣的操作,使得矩陣只剩下一個,爲了能夠通關遊戲,你還要保證你得到的金幣是最大的,最後輸出你得到的最大金幣數量。

思路:

經典最優子結構問題,和切木條很像,但是有一點不同就是這是一個環,所以他應該有n種情況的區間dp:

1,2,.....n的最優,2,3,4,....,n,1的最優,.....

所以我們在數組後面再擴充一倍,這是解決環問題的經典方法。

dp[i][j]表示將區間i,j合併爲1個矩陣的最小花費,答案就是在n個長度爲n的區間內取最大值(對應的就是將環拆成鏈的n種情況)

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=200+20;
int dp[maxn][maxn];
struct Node{
    int p,q;
}node[maxn];
int dfs(int l,int r){
    int &ans=dp[l][r];
    if(ans!=-1)return ans;
    ans=0;
    for(int k=l;k<r;k++){
        ans=max(ans,dfs(l,k)+dfs(k+1,r)+node[l].p*node[k+1].p*node[r].q);
    }
    return ans;
}
signed main(){
    int n;
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&node[i].p,&node[i].q);
        node[i+n].p=node[i].p,node[i+n].q=node[i].q;
    }
    for(int i=0;i<=2*n;i++){
        for(int j=0;j<=2*n;j++){
            dp[i][j]=-1;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dfs(i,i+n-1));
    }
    printf("%lld\n",ans);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章