区间DP(一维、二维)

代码

一维DP

// 石子合并模板代码 
for (int i = 1; i <= n; i++) dp[i][i] = 0; // 初始化
for (int len = 2; len <= n; len++) {
	for (int i = 1; i <= n - len + 1; i++) { // 倒数第len个数是要当作起点的 
		int j = i + len - 1; // 因为还包含i本身 
		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] + w[i][j]); // 使用k将i、j分隔开 
		}  // 此处的w 是说 ; 因为我们分开了成了两堆,所以要将他们合并起来需要付出的代价 
		   // 但有时候是没有这个w的,需要看题目判断
	}
} 

二维DP(弄成两个一维DP)


// CF199F
for (int lenx = 1; lenx <= n; lenx++) {
	for (int leny = 1; leny <= n; leny++) {
		for(int x1 = 1; x1 <= n - lenx + 1; x1++) {
			for (int y1 = 1; y1 <= n -leny + 1; y1++) {
				
				int x2 = x1 + lenx - 1;
				int y2 = y1 + leny - 1;
				
				if (x1 == x2 && y1 == y2) continue; // 这种情况不用看了,单纯一个点的情况前面都初始化过了 
				
				dp[x1][y1][x2][y2] = max(abs(x1 - x2), abs(y1 - y2)) + 1; // 初始值 
				
				for(int k = x1; k <= x2; k++) {
					dp[x1][y1][x2][y2] = min(dp[x1][y1][x2][y2], dp[x1][y1][k][y2] + dp[k + 1][y1][x2][y2]);
				} 
				for (int k = y1; k <= y2; k++) {
					dp[x1][y1][x2][y2] = min(dp[x1][y1][x2][y2], dp[x1][k][x2][y2] + dp[x1][k + 1][x2][y2]);
				}
				 
			}
		}
	}
}

原理

区间 DP 是常见的 DP 应用场景。区间 DP也是线性 DP,它把区间当成 DP 的阶段,用区间的两个端点描述状态和处理状态的转移。区间DP的主要思想是先在小区间进行DP得到最优解,然后再合并小区间的最优解求得大区间的最优解。解题时,先解决小区间问题,然后合并小区间,得到更大的区间,直到解决最后的大区间问题。合并的操作一般是把左右两个相邻的子区间合并。

核心

分割:dp[i][j] = max(dp[i][k], dp[k + 1][j]);

从区间的关系两边得到转移方程

题目

1、石子合并问题(网上找来做)

2、刷字符串 hdu 2476

3、栈的 hdu 4283 (若第i个位置(序列排列)的元素第k个出栈,则i 后的 k - 1 个元素一定比i先出栈)

4、CF1199F 

练习:

https://leetcode-cn.com/circle/article/NfHhXD/

区间DP:https://vjudge.net/contest/77874

洛谷p 1880 3146 1063 1005 4170 4302 2466

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值