区间DP

内容参考书籍《算法竞赛入门到进阶》

区间DP就是先在小区间进行DP,然后合并小区间,得到大区间,直到解决最后的大区间问题。相较于普通的DP问题,它不仅需要状态转移方程还需要枚举所有可能的区间。

通常情况下,区间DP至少需要两层for循环,例如:

	for (int i = 1; i < n; ++i)
	{
		for (int j = i; j <= n; ++j)
		{
			...
		}
	}

  下面引入两个经典问题:

1.石子合并:有n堆石子排成一排,每堆石子有一定的数量,将这n堆石子合成一堆,每次只能合并相邻的两堆,合并花费为两堆石子总数,求最小花费。

输入:

3
2 4 5

输出:

17

计算过程为:一:2+4=6,二:6+5=11,三:6+11=17,故答案为17。

设dp[i][j]为从第i堆石子到第j堆石子的最小花费,那么答案为dp[1][n]。另外,设sum[i][j]为从第i到j的区间和。

那么合并两堆,例如dp[1][2],是指合并1-2,就有dp[1][2] = dp[1][1] + dp[2][2] + sum[1][2],也即是dp[i][i+1] = dp[i][i] + dp[i+1][i+1] + sum[i][i+1]

合并三堆,例如dp[1][3],则有两种情况,先合并1-2再3,或者先2-3再1,即dp[1][3] = min(dp[1][1] +dp[2][3], dp[1][2] + dp[3][3])+sum[1][3]。

也即是dp[i][i+2] = min(dp[i][i]+dp[i+1][i+2] , dp[i][i+1] + dp[i+2][i+2])+sum[i][i+2]。

推广:dp[i][j] = min(dp[i][k]+dp[k+1][j])+sum[i][j-i+1]。

代码如下:

(后续代码明天写)

posted @ 2020-05-25 23:32  DemonSlayer  阅读(146)  评论(0编辑  收藏  举报