題目鏈接: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);
}