一类1D/1D动态规划方程的三种优化情况 单调队列优化 斜率优化 决策单调性优化

版权声明:转载必须注明原文链接,并且每50字(半角,向上取整)就要注明一次,侵权必究 https://blog.csdn.net/myjs999/article/details/83478233

众所周知,DP优化有单调队列优化、数据结构优化、矩阵快速幂优化、斜率优化、四边形不等式优化、决策单调性优化、凸优化等。本文讲解关于一类DP方程的三种优化情况。

f [ i ] = min { f [ j ] + w ( i , j ) } f[i]=\min\{f[j]+w(i,j)\}

其中 j [ l [ i ] , r [ i ] ] j\in [l[i],r[i]] l [ i ] l[i] r [ i ] r[i] 单调不减。 min \min 可换为 max \max ,方法相同。

w ( i , j ) w(i,j) j j 无关

对于 j , k [ [ l [ i ] , r [ i ] ] ( j < k ) j,k\in [[l[i],r[i]](j<k) ,若 f [ k ] f[k] 不比 f [ j ] f[j] 更劣(更大),则 j j k k 以后的更新都不会有任何贡献,因为有 j j 的地方就有 k k ,且完全可以选 k k 而不选 j j 。因此用一个单调队列维护当前有用的转移下标即可。

时间复杂度 O ( n ) O(n)

w ( i , j ) w(i,j) 只含 i i 的多项式、 j j 项和 i j ij

时间复杂度为 O ( n ) O(n) O ( n log n ) O(n\log n)

w ( i , j ) w(i,j) 满足四边形不等式

四边形不等式 w ( i + 1 , j ) w ( i , j ) w ( i + 1 , j + 1 ) w ( i , j + 1 ) w(i+1,j)-w(i,j)\ge w(i+1,j+1)-w(i,j+1)
这个性质说明,对于更大的 j j w ( ) w() 随着 i i 增长的速度越慢。因此对于 k > j k>j ,如果从 k k 转移不劣于从 j j 转移,那么 j j k k 转移以后就没用了,因为随着 i i 的增加 w ( i , j ) w(i,j) 只会比 w ( i , k ) w(i,k) 越来越差。即 f [ i ] f[i] 的决策点是单调右移的,即决策单调性

一般有两种方法来实现:

栈+二分

考虑每个决策点能更新哪些状态。我们枚举 1 1 n n 的决策点来更新后面的状态。由于决策单调性,每次更新后,决策点数列是单调不减的。因此每次更新的位置是一个区间 [ k i , n ] [k_i,n] 。于是我们用一个栈维护从左到右的连续相同的决策点块,每次更新时从栈顶开始检查,如果新决策比原决策块完全更优就把原决策块弹掉,否则二分原决策块区间找到从哪个点开始新决策更优。最后将新决策块入栈。

每个决策最多入栈、出栈一次,因为用了二分,时间复杂度为 O ( n log n ) O(n\log n)

struct decis {
	int a, l, r; // 决策点位置,决策块管辖区间
}S[maxn];
int top;

//...
{
	top = 0;
	S[top++] = (decis){0, 0, n-1}; // 第一个决策块
	for(int i = 1; i < n; i++) {
		while(top) {
			decis ctop = S[top-1];
			int ftop = f[ctop.a] + calc(), fnew = f[i] + calc(); //calc()为分别用ctop.a和i更新ctop.l的代价
			if(ftop > fnew) top--; else break;
		}
		if(top) {
			int l = S[top-1].l, r = S[top-1].r+1;
			while(l < r) {
				int mid = l + r >> 1;
				int ftop = f[S[top-1].a] + calc(), fnew = f[i] + calc();  //calc()为分别用S[top-1].a和i更新mid的代价
				if(ftop > fnew) r = mid; else l = mid+1;
			}
			// 此时l的值是第一个新块较优的位置
			if(l <= S[top-1].r) {
				decis o = S[top-1]; top--;
				S[top++] = (decis){o.a, o.l, l-1};
			}
			if(l <= n-1) S[top++] = (decis){i, l, n-1};
		}else S[top++] = (decis){i, k-1, n-1};
	}
	for(int i = 0; i < top; i++) for(int j = S[i].l; j <= S[i].r; j++) f[j] = f[S[i].a] + calc();
}

分治

考虑分治处理每个点的决策点。设当前在处理 [ l , r ] [l,r] 的决策点,并已知可能的决策点区间为 [ L , R ] [L,R] 。设 m i d = l + r 2 mid=\frac{l+r}{2} ,则先暴力求出 m i d mid 的决策点 p p (范围肯定是 [ L , m i d ] [L,mid] ),然后分治处理两边,显然 [ l , m i d ] [l,mid] 的决策点在 [ L , p ] [L,p] ,而 [ m i d + 1 , r ] [mid+1,r] 的决策点在 [ p , R ] [p,R] 。复杂度为 O ( n log n ) O(n \log n)

w ( i , j ) w(i,j) 满足四边形不等式和区间单调性

Upd on 2018.11.26

区间单调性 对于所有区间 [ i , j ] [i,j] 包含 [ i , j ] [i&#x27;,j&#x27;] ,有 w ( i , j ) &gt; w ( i , j ) w(i,j)&gt;w(i&#x27;,j&#x27;)

w ( i , j ) w(i,j) 满足四边形不等式和区间单调性,则决策点满足区间单调性。因此枚举决策点的时候只用从之前的决策点之间枚举。类似四边形不等式优化区间DP,复杂度从 O ( n 3 ) O(n^3) 降为 O ( n 2 ) O(n^2)

例题:IOI2000 邮局

练习题

BZOJ3675 POJ1160 BZOJ1492 HDU3480 BZOJ2726 HDU2829 BZOJ1791 HDU3516

2018.11.30 DP凸优化

猜你喜欢

转载自blog.csdn.net/myjs999/article/details/83478233