p1775 石子合并 题解

文章讲述了区间DP问题的解决策略,通过划分区间并定义状态dp[i][j]表示区间[i,j]的合并代价,利用状态转移方程通过枚举断开点找到最优解,最后给出一个实际的C++代码示例和AC记录。
摘要由CSDN通过智能技术生成

分析

这个问题是区间DP的模板题。区间DP的特点是把序列划分成左右两个子序列,子序列对应于子问题。递归求解左、右两个子问题,得到最优解后,再想办法合并为当前断开方案的最优解。

划分的断开点不同,对应于不同的左、右子问题,递归解决子问题后,就得到不同断开方案的最优解。从而进一步算出整个问题的最优解。

定义状态dp[i][j]表示区间[i,j]合并为一个数的操作代价之和。

考虑状态转移方程。枚举断开点k,也就是最后一次合并的分界线,把序列分成左右两个子序列,先把左右两个子序列分别递归合并成一个数,最小操作代价为dp[i][k]和dp[k+1][j]。最后一次合并的操作代价很简单,就是左右两个数直接相加,本质上是区间所有数之和。

状态转移方程可写为:dp[i][j] = min(dp[i][k], dp[k+1][j]) + sum(i,j) | i <= k <= j - 1
边界状态为dp[i][i] = 0
在实现时,要把区间长度作为阶段变量放在最外层枚举。

for(int len = 2; len <= n; len++)
    for(int i = 1; i + len - 1 <= n; i++){
        int j = i + len - 1;
        dp[i][j] = INT_MAX;
        for(int k = i; k < j; k++)
            dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
        dp[i][j] += sum[j] - sum[i-1];
    }

完整的代码

洛谷AC记录

#include<bits/stdc++.h>
using namespace std;
#define MAXN 5005
#define INF 0x3F3F3F3F
int a[MAXN], sum[MAXN], dp[MAXN][MAXN];
int n;
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        sum[i] = sum[i-1] + a[i];
    }
    for(int len = 2; len <= n; len++)
        for(int i = 1; i<= n-len+1; i++){
            int j = i+len-1;
            dp[i][j] = INF;
            for(int k = i; k < j; k++)
                dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
            dp[i][j] += sum[j] - sum[i-1];
        }
    printf("%d\n", dp[1][n]);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值