区间dp学习笔记
区间dp学习笔记
具体思路
区间dp,故名思意,就是在一段区间里做动态规划操作,一般的区间dp都运用了如下操作
- 状态表示:\(dp_{i,j}\) 一般表示的是 \(i\) 到 \(j\) 这一段区间里面的答案 ,答案为 \(dp_{1,n}\)
- 边界处理:\(dp_{i,i}\) 只表示一个数字,我们直接按照题意初始化
- 三层循环,遍历区间长度 \(len\) ,左节点 \(l\) ,易得右节点 \(r\) 为 \(len+i-1\) ,中间一些判断语句,最后一层循环在区间内寻找断点 \(k\) 。
一般的状态转移方程为
\(dp_{i,j} = \max(dp_{i,j},dp_{i,k}+dp_{k+1,j}+......)\)
至于你前面的 \(\max\) 还是 \(\min\),我们根据题意来判断,注意我们处理的区间还可以是环状的,这时后我们就要来处理一下边界,并将数组开大,再处理一下即可。
综上所述,一般的区间dp时间复杂度为 \(O(n^3)\) ,空间复杂度为 \(O(n^2)\)
习题
我们设 \(f_{i,j}\) 为 \(i\) 到 \(j\) 的区间内的最小代价,再用前缀和优化
边界条件:\(f_{i,i}=0\)
状态转移方程
\(s\) 数组为前缀和数组,答案为 \(f_{1,n}\)
我们设 \(dp_{i,j}\) 为 \(i\) 到 \(j\) 的区间内的最小涂色次数
边界条件:\(dp_{i,i}=1\)
状态转移方程分成两种情况
1.\(str_l=str_r\) 的时候
可以想到只需要在首次涂色时多涂一格即可,状态转移方程:\(dp_{l,r}=\min(dp_{i+1,j},dp_{i,j-1})\)
2.否则枚举断点:
\(dp_{l,r} = min(dp_{l,r}, dp_{l,k} + dp_{k+1,r});\)
for (int x = 1; x < n; x ++ )
{
for (int l = 1, r = x + 1; r <= n; l ++ , r ++ )
{
if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]);
else
for (int k = l; k < r; k ++ ) dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]);
}
}
3.P1063 [NOIP2006 提高组] 能量项链
设 \(dp_{i,j}\) 为 \(i\) 到 \(j\) 的区间内的最大能量
边界条件:\(dp_{i,i + 1} = 0\)
将 \(n\) 个珠子合并弄成 \(n + 1\) 个"石头"合并
状态转移方程:\(dp_{l,r} = max(dp_{l,r}, dp_{l,k} + dp_{k,r} + a_l * a_k * a_r);\)
典型的环形区间dp
for (int len = 2; len <= n + 1; len ++ )
{
for(int l = 1, r; l + len - 1 <= n << 1; l ++ )
{
r = l + len - 1;
if(len == 2)
dp[l][r] = 0;
else
{
for(int k = l + 1; k < r; k ++ )
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k][r] + a[l] * a[k] * a[r]);
}
}
}

浙公网安备 33010602011771号