区间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]。
代码如下:
(后续代码明天写)