dp总结
最近发现之前学过的很多dp优化都忘了==所以写篇文章复习一下,以备查找。
最长上升子序列(LIS)
dp方程
d[i]=maxd[k]+1(k<i,a[k]<a[i])
复杂度O(n2)
优化
因为d值相同时只需保留最小的a值,所以令g[i]为d[k]==i中k的最小值,显然g[1]≤g[2]≤⋯≤g[k]
那么计算d[i]时,只需在g中找到最小的k使g[k]≥a[i],则d[i]=k,此时,a[i]≤g[k],所以更新g[k]=a[i]
STL中的lower_bound
函数可以在O(logn)的时间内找到第一个大于等于k的数,因此复杂度可以优化到O(nlogn)
代码如下:
memset(g,0x3f,sizeof(g));
for(register int i=1;i<=n;i++)
{
int j=lower_bound(g+1,g+n+1,a[i])-g;
d[i]=j;
g[j]=a[i];
}
循环部分甚至可以简写成:
for(register int i=1;i<=n;i++)d[i]=lower_bound(g+1,g+n+1,a[i])-g,g[d[i]=a[i];
应用
二维偏序分组(dilworth+lis:导弹拦截),LCS(其中一组映射成有序数列,另一组求最长上升子序列)等。