C语言 深入探究动态规划之区间DP
写在前面
石子合并
题意:
合并 N 堆石子,每次只能合并相邻的两堆石子,求最小代价
解题思路:
关键点:最后一次合并一定是左边连续的一部分和右边连续的一部分进行合并
状态表示:f[i][j]表示将 i 到 j 这一段石子合并成一堆的方案的集合,属性 Min
状态计算: (1) i<j 时,f[i][j]=min f[i][k]+f[k+1][j]+s[j]−s[i−1] (2)i=j 时,
f[i][i]=0(合并一堆石子代价为 0)
问题答案: f[1][n]
所有的区间dp问题枚举时,第一维通常是枚举区间长度,并且一般 len = 1 时用来初始化,枚举从 len = 2 开始;第二维枚举起点 i (右端点 j 自动获得,j = i + len - 1)
模板代码如下:
for (int len = 1; len <= n; len++) { // 区间长度 for (int i = 1; i + len - 1 <= n; i++) { // 枚举起点 int j = i + len - 1; // 区间终点 if (len == 1) { dp[i][j] = 初始值 continue; } for (int k = i; k < j; k++) { // 枚举分割点,构造状态转移方程 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + w[i][j]); } } }
最后总的代码:
#include <iostream> #include <cstring> using namespace std; const int N = 307; int a[N], s[N]; int f[N][N]; int main() { int n; cin >> n; for (int i = 1; i <= n; i ++) { cin >> a[i]; s[i] += s[i - 1] + a[i]; } memset(f, 0x3f, sizeof f); // 区间 DP 枚举套路:长度+左端点 for (int len = 1; len <= n; len ++) { // len表示[i, j]的元素个数 for (int i = 1; i + len - 1 <= n; i ++) { int j = i + len - 1; // 自动得到右端点 if (len == 1) { f[i][j] = 0; // 边界初始化 continue; } for (int k = i; k <= j - 1; k ++) { // 必须满足k + 1 <= j f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]); } } } cout << f[1][n] << endl; return 0; }
到此这篇关于C语言 深入探究动态规划之区间DP的文章就介绍到这了,更多相关C语言 区间DP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
C++中的类型查询之探索typeid和type_info(推荐)
C++ 是一种静态类型语言,这意味着每个变量的类型在编译时就已经确定,在这篇技术分享中,我们将探讨 C++ 中的 typeid 和 type_info,以及如何使用它们来获取类型信息,需要的朋友可以参考下2024-05-05
最新评论