区间dp学习笔记

定义

令状态\(f(i, j)\)表示将下标位置\(i\)\(j\)的所有元素合并能获得的价值的最大值,那么\(f(i, j) = max(f(i, k) + f(k+1, j) + cost)\), \(cost\)为将这两组元素合并起来的代价。

性质

区间DP有以下特点:

合并:即将两个或多个部分进行整合
特征:能将问题分解为能两两合并的形式
求解:对整个问题设最优值,枚举合并点,将问题分为左右两部分,最后合并两个部分的最优值得到原问题的最优值。

例题

石子合并

代码

#include <bits/stdc++.h>
#define i64 long long
using namespace std;
const int MAXN = 505 ;
int n ;
i64 a[MAXN] ;
i64 dp[MAXN][MAXN][5] ;
i64 sum[MAXN] ;
int main()
{
    cin >> n ;
    for(int i = 1 ; i <= n ; i ++ ) {cin >> a[i] ; a[i + n] = a[i] ;}
    for(int i = 1 ; i <= 2 * n  ; i ++ ) sum[i] = sum[i - 1] + a[i] ;
    for(int i = 1 ; i <= 2 * n ; i ++ ) dp[i][i][2] = 0 , dp[i][i][1] = 0 ;
    for(int len = 2 ; len <= n ; len ++ )
    {
        for(int i = 1 ; i <= 2*n - len + 1 ; i ++ )
        {
            int j = len + i - 1 ;
            dp[i][j][2] = 0x3f3f3f ;
            for(int k = i ; k < j ; k ++ )
            {
                dp[i][j][1] = max(dp[i][j][1], dp[i][k][1] + dp[k + 1][j][1] + sum[j] - sum[i - 1]) ;
                dp[i][j][2] = min(dp[i][j][2], dp[i][k][2] + dp[k + 1][j][2] + sum[j] - sum[i - 1]) ;
            }
        }
    }
    i64 ans1 = 0 ;
    i64 ans2 = 0x3f3f3f ;
    for(int i = 1 ; i <= n ; i ++ )
    {
        ans1 = max(ans1, dp[i][i + n - 1][1]) ;
        ans2 = min(ans2, dp[i][i + n - 1][2]) ;
    }
    cout << ans2 << endl ;
    cout << ans1 << endl ;
    return 0 ;
}
posted @ 2023-04-26 20:57  Lwen1243  阅读(14)  评论(0)    收藏  举报