區間dp【洛谷P1040】
阿新 • • 發佈:2018-11-10
照例送上題目連結:https://www.luogu.org/problemnew/solution/P1040
這個題目是個區間dp(為什麼會在洛谷的dfs裡面,我也不知道啊)
dfs啊呸,區間dp,顧名思義,就是在一段區間[l,r]上的dp(我在說什麼亂七八糟的,劃掉劃掉)。
乍一看這個題目,看似無從下手(可能只有我自己無從下手),其實仔細一分析,題目要,求最大值,我們就直接列舉樹根,然後把左右兒子按照題目要求的操作一波就好啦。
dp方程直接給出來了,很好理解 dp[i][j] = max(dp[i][j],dp[i][k-1]*dp[k+1][j]+dp[k][k]) ,其中dp[i][j]表示節點i到節點j的最大值。
1.首先列舉區間長度。
2.列舉左端點。
3.列舉根
先序遍歷就直接遞迴輸出root就好啦(先訪問根,然後輸出左邊,然後輸出右邊)。
還是直接看程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50; ll dp[maxn][maxn]; ll root[maxn][maxn]; void init() { memset(dp,0,sizeof(dp)); memset(root,0,sizeof(root)); } void print(int l,int r) { if(l>r) { return; } cout<<root[l][r]<<" "; if(l==r) { return; } print(l,root[l][r]-1); print(root[l][r]+1,r); } int main() { int n; while(cin>>n) { for(int i=1;i<=n;i++) { cin>>dp[i][i]; dp[i][i-1] = 1; root[i][i] = i; } for(int len = 1;len<n;len++) { for(int i=1;i+len<=n;i++) { int j = i+len; dp[i][j] = dp[i+1][j]+dp[i][i]; root[i][j] = i; for(int k=i+1;k<j;k++) { if(dp[i][j]<dp[i][k-1]*dp[k+1][j]+dp[k][k]) { dp[i][j]=dp[i][k-1]*dp[k+1][j]+dp[k][k]; root[i][j] = k; } } } } cout<<dp[1][n]<<endl; print(1,n); } return 0; }
PS:等等,這是個樹形dp?