洛谷题单指南-动态规划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;
}