算法关系
算法关系
CDQ与区间DP
划分区间使得独立的问题不仅可以使用CDQ,而且可以使用区间DP
其中CDQ分治是考虑两侧元素之间的点对点贡献
而区间DP是只关心整体值
但他们使用前提相同——区间可划分
DP的向前更新与向后更新
从DFS谈起
关于DFS搜索,有两种方式:最后计算答案与最后产生贡献。
以多重背包举例。
最后计算答案:
void DFS(int x,int v,int sum){
if(x==n+1){ans=max(ans,sum);return;}
for(int i=0;i<=m[x];i++)if(v+i*c[x]<=V)DFS(x+1,v+i*c[x],sum+i*w[x]);
}
最后产生贡献:
int DFS(int x,int V){
if(x==n+1){return 0;}
int tmp=0;
for(int i=0;i<=m[x];i++)if(v+i*c[x]<=V)
tmp=max(tmp,DFS(x+1,v+i*c[x])+i*w[x]);
return tmp;
}
这两种搜索的复杂度是一样的,但后者可以使用记忆化搜索,而前者不行。
后者记忆化搜索可以直接变为DP。
在前者的基础上,纵向比较,即对于相同的 \(x,v\) 保留最大的 \(sum\),可以获得一个假的记忆化搜索。接着改变顺序变为递推,就可以变为一个刷表法DP,接着改变顺序就变为了填表法DP,即我们普遍背包问题解法。
这里对应了两种DP设计方式:
-
最后贡献
-
实时答案
以及两种DP实现方法:
-
刷表法
-
填表法
一般情况下,我们用的“实时答案”的DP,正如我们更容易想到“最后计算答案”的DFS,他更自然。
转化
刷表法与填表法一定是可以互转的,有逆运算的直接逆运算,无逆运算的直接枚举保证均摊复杂度,实在不行将所有转移存下来也可以做到。
在背包问题中,这两种DP设计方式是可以转化的。
在一般情况下:如果可以先枚举所有方案再解决,“实时答案”的方式
如果前面的决策与后面的无关,“最后贡献”的方式。