洛谷题单指南-动态规划3-P1775 石子合并(弱化版)

原题链接:https://www.luogu.com.cn/problem/P1775

题意解读:计算合并石子的最小代价,区间DP。

解题思路:

状态表示:dp[i][j]表示将第i~j堆石子合并的最小代价,m[i]表示第i堆石子质量,s[i]表示前i堆石子质量前缀和

状态转移:考虑最后一次合并,设最后一次合并是将i~k合成的一堆与k+1~j合成的一堆进行合并

因此,总的合并代价是将i~k合成一堆的代价dp[i][k],加上k+1~j合成一堆的代价dp[k+1][j],再加上最后一次合并的代价也就是i~j堆质量之和s[j]-s[i-1]

则有,对于k取值i~j-1,dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + s[j] - s[i-1])

初始化:求最小值所以初始为memset(dp, 0x3f, sizeof(dp));而dp[i][i] = 0表示i~i合并代价为0,因为不用合并

结果:dp[1][n]

由于dp[1][n]的值依赖的1~n之间所有小区间的值先计算出来,因此在枚举时,通常如下操作:

1、第一层枚举所有区间的长度len:1~n

2、第二层枚举所计算区间的左端点

3、根据左端点计算右端点,再枚举分界点k

100分代码:

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

const int N = 305;
int n;
int m[N], s[N];
int dp[N][N]; //dp[i][j]表示将第i~j堆石子合并的最小代价

int main()
{
    cin >> n;
    memset(dp, 0x3f, sizeof(dp));
    for(int i = 1; i <= n; i++)
    {
        cin >> m[i];
        s[i] = s[i-1] + m[i];
        dp[i][i] = 0;
    } 
    
    for(int len = 1; len <= n; len++)
    {
        for(int i = 1; i + len - 1 <= n; i++)
        {
            int j = i + len - 1;
            for(int k = i; k < j; k++)
            {
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + s[j] - s[i-1]);
            }
        }
    }
    cout << dp[1][n];

    return 0;
}

 

posted @ 2024-05-10 16:04  五月江城  阅读(54)  评论(0编辑  收藏  举报