• Algorithm Review 4


    动态规划

    • 通过发掘转移时最优解的必要条件往往能使抽象的转移条件变得简单。
    • 当问题有多维的限制时,将其中一维排序往往能简化状态设计和转移。

    矩阵快速幂优化 DP

    • 以下面的顺序计算矩阵乘法,访问内存连续,效率最高。
    	friend inline matrix operator * (const matrix &a, const matrix &b)
    	{
    		matrix c;
    		c.Clear(a.gn, b.gm);
    		for (int i = 0; i < a.gn; ++i)
    			for (int k = 0; k < a.gm; ++k)
    			{
    				int s = a.g[i][k];
    				for (int j = 0; j < b.gm; ++j)
    					c.g[i][j] = (1ll * s * b.g[k][j] + c.g[i][j]) % mod;
    			}		
    		return c;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    单调队列优化 DP

    典例 POJ3017

    • f i f_i fi 表示将前 i i i 个数分成若干段、满足每段所有数的和不超过 M M M 时各段最大值之和的最小值。不难得到转移:
      f i = min ⁡ 0 ≤ j < i 且 ∑ k = j + 1 i a k ≤ M { f j + max ⁡ j + 1 ≤ k ≤ i { a k } } f_i = \min\limits_{0\le j < i且\sum\limits_{k =j+1}^{i}a_k\le M}\{f_j + \max\limits_{j + 1\le k\le i}\{a_k\}\} fi=0j<ik=j+1iakMmin{fj+j+1kimax{ak}}
    • 容易证明,最优解需满足以下两个条件之一:
      • a j = max ⁡ j ≤ k ≤ i { a k } a_j = \max\limits_{j\le k\le i}\{a_k\} aj=jkimax{ak}
      • ∑ k = j i a k > M \sum \limits_{k = j}^{i}a_k > M k=jiak>M
    • 第一个条件可以维护一个决策点 j j j 单调递增、数值 a j a_j aj 单调递减的队列,并用数据结构维护最优转移,这里使用的是懒惰删除的二叉堆,第二个条件只需要维护单个指针单独转移即可。
    	l = 0, ql = 1, qr = 0;
    	for (int i = 1; i <= n; ++i)
    	{	
    		while (l < i && sum[i] - sum[l] > M)
    			++l;
    		while (ql <= qr && sum[i] - sum[que[ql]] > M)
    			val[que[ql++]] = -1;
    		while (ql <= qr && a[que[qr]] <= a[i])
    			val[que[--qr]] = -1;
    		if (ql <= qr)
    			q.push(point(val[que[qr]] = f[que[qr]] + a[i], que[qr]));
    		que[++qr] = i;
    		f[i] = f[l] + a[que[ql]];
    		while (!q.empty() && val[q.top().t] != q.top().s)
    			q.pop();
    		if (!q.empty())
    			CkMin(f[i], q.top().s);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    多重背包

    • 给定 n n n 种物品,其中第 i i i 种物品的体积为 v i v_i vi,价值为 w i w_i wi,有 c i c_i ci 个。
    • 求能够放入容积 m m m 的背包的物品的最大价值总和。

    二进制拆分法

    • 求出 ∑ k = 0 p 2 k ≤ c i \sum \limits_{k = 0}^{p}2^k\le c_i k=0p2kci 最大的 p p p,令 r i = c i − ∑ k = 0 p 2 k r_i = c_i - \sum\limits_{k = 0}^{p}2^k ri=cik=0p2k
    • 将数量为 c i c_i ci 的第 i i i 种物品拆成 p + 2 p + 2 p+2 种物品,其体积分别为:
      2 0 v i , 2 1 v i , … , 2 p v i , r i v i 2^0v_i, 2^1v_i,\dots,2^pv_i,r_iv_i 20vi,21vi,,2pvi,rivi
    • 时间复杂度 O ( n m log ⁡ c ) \mathcal O(nm\log c) O(nmlogc),其中 c = max ⁡ 1 ≤ i ≤ n { c i } c = \max\limits_{1\le i\le n}\{c_i\} c=1inmax{ci}

    单调队列优化

    • 将容积那一维按照模 v i v_i vi 的余数分类,则可利用单调队列优化。
    • 时间复杂度 O ( n m ) \mathcal O(nm) O(nm)

    斜率优化 DP

    • 形如下式的转移宜采用斜率优化:
      f i = max ⁡ / min ⁡ { f j + A ( i ) B ( j ) + C ( i ) + D ( j ) } f_i = \max/\min\{f_j + A(i)B(j) + C(i)+D(j)\} fi=max/min{fj+A(i)B(j)+C(i)+D(j)}
      其中 A , B , C , D A,B,C,D A,B,C,D 分别为含对应变量的多项式, A , B A,B A,B 中的最高次数为一次。
    • 去除 max ⁡ / min ⁡ \max/\min max/min 的限制,移项得到:
      − A ( i ) B ( j ) + f i − C ( i ) = f j + D ( j ) -A(i)B(j) + f_i - C(i) = f_j + D(j) A(i)B(j)+fiC(i)=fj+D(j)
      将每个可能的决策 ( B ( j ) , f j + D ( j ) ) (B(j), f_j + D(j)) (B(j),fj+D(j)) 视作平面上的一点,最优决策即用固定斜率 − A ( i ) -A(i) A(i) 的直线去截这些点,最大化/最小化截距,因而只需要维护这些点的上凸壳/下凸壳。
    • 维护的方式视具体情况而定:
      • A ( i ) , B ( j ) A(i),B(j) A(i),B(j) 均单调,用单调队列/单调栈维护即可。
      • A ( i ) , B ( j ) A(i), B(j) A(i),B(j) 其中一个单调,将单调的那个变量视作决策点(若只有 A ( i ) A(i) A(i) 单调则需要倒着转移),求最优决策时在凸壳上二分即可。
      • A ( i ) , B ( j ) A(i),B(j) A(i),B(j) 均不单调,则需要用平衡树维护凸壳或离线后 CDQ \text{CDQ} CDQ分治。

    决策单调性

    四边形不等式

    • w ( x , y ) w(x,y) w(x,y) 为定义在整数集合上的二元函数,对于定义域上的任意整数 a , b , c , d a,b,c,d a,b,c,d,其中 a ≤ b ≤ c ≤ d a\le b \le c\le d abcd,都有 w ( a , d ) + w ( b , c ) ≥ w ( a , c ) + w ( b , d ) w(a,d) + w(b,c) \ge w(a,c) + w(b,d) w(a,d)+w(b,c)w(a,c)+w(b,d),称为函数 w w w 满足四边形不等式。

    一维决策单调性

    • 在状态转移方程 f i = min ⁡ 0 ≤ j < i { f j + w ( j , i ) } f_i = \min\limits_{0 \le j < i}\{f_j + w(j,i)\} fi=0j<imin{fj+w(j,i)} 中,若函数 w w w 满足四边形不等式,则 f f f 具有决策单调性。
    • 用队列维护若干个三元组 ( l , r , j ) (l,r,j) (l,r,j),表示 [ l , r ] [l,r] [l,r] 内的最优决策均为 j j j
    • 在队尾插入时:
      • 若比前一个三元组整个区间内的决策都优,则直接合并,继续检查前一个三元组。
      • 若比前一个三元组整个区间内的决策都不优,则直接插入队尾。
      • 否则在区间上二分找到分界点,修改两个区间的分界后插入队尾。

    二维决策单调性

    • 在状态转移方程 f i , j = min ⁡ i ≤ k < j { f i , k + f k + 1 , j + w ( i , j ) } f_{i,j} = \min\limits_{i \le k < j}\{f_{i,k}+f_{k+1,j}+w(i,j)\} fi,j=ik<jmin{fi,k+fk+1,j+w(i,j)} 中,若下面三个条件成立:
      • 可规定 f i , i = w ( i , i ) = 0 f_{i,i} = w(i,i) = 0 fi,i=w(i,i)=0
      • w w w 满足四边形不等式。
      • 对于任意的 a ≤ b ≤ c ≤ d a \le b \le c \le d abcd,有 w ( a , d ) ≥ w ( b , c ) w(a,d) \ge w(b,c) w(a,d)w(b,c)
    • f f f 也满足四边形不等式,设 p i , j p_{i,j} pi,j 表示令 f i , j f_{i,j} fi,j 取到最小值的 k k k 值,则恒有 p i , j − 1 ≤ p i , j ≤ p i + 1 , j p_{i,j-1}\le p_{i,j}\le p_{i + 1,j} pi,j1pi,jpi+1,j
    • 因此我们在转移时只需枚举 [ p i , j − 1 , p i + 1 , j ] [p_{i,j-1},p_{i+1,j}] [pi,j1,pi+1,j] 内的 k k k,对于长度为 L + 1 L+1 L+1 的区间,总枚举量为:
      ( p 2 , L + 1 − p 1 , L ) + ( p 3 , L + 2 − p 2 , L + 1 ) + ⋯ + ( p n − L + 1 , n − p n − L , n − 1 ) = p n − L + 1 , n − p 1 , L (p_{2, L+1} - p_{1,L})+(p_{3,L+2}-p_{2,L+1})+\dots+(p_{n - L + 1, n} - p_{n - L, n - 1}) = p_{n - L + 1, n} - p_{1,L} (p2,L+1p1,L)+(p3,L+2p2,L+1)++(pnL+1,npnL,n1)=pnL+1,np1,L
    • 因此总的时间复杂度为 O ( ∑ i = 1 n − 1 ( p n − i + 1 , n − p 1 , i ) ) = O ( n 2 ) \mathcal O(\sum \limits_{i = 1}^{n - 1}(p_{n-i+1,n} - p_{1,i})) = \mathcal O(n^2) O(i=1n1(pni+1,np1,i))=O(n2)

    GarsiaWachs 算法

    • 上述二维决策单调性能解决的石子合并问题有一种专门的非动态规划算法。
    • 设第 i i i 堆石子的数目为 a i a_i ai,令 a 0 = a n + 1 = + ∞ a_0 = a_{n + 1} = +\infin a0=an+1=+,具体步骤如下:
      • 找到满足 a k − 1 < a k + 1 a_{k - 1} < a_{k + 1} ak1<ak+1 最大的 k k k
      • 找到满足 a j > a k − 1 + a k a_j > a_{k - 1} + a_k aj>ak1+ak j < k j < k j<k 的最大的 j j j
      • 删除 a k − 1 , a k a_{k - 1}, a_k ak1,ak,在 a j a_j aj 后插入 a k + a k − 1 a_k + a_{k - 1} ak+ak1
      • 重复上述过程直至石子被合并为一堆。
    • 空间复杂度 O ( n ) \mathcal O(n) O(n),时间复杂度 O ( n 2 ) \mathcal O(n^2) O(n2),可用平衡树优化至 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)

    证明 待补充。

    	read(n);
    	v.push_back(Maxn);
    	for (int i = 1, x; i <= n; ++i)
    	{
    		read(x);
    		v.push_back(x);
    	}
    	v.push_back(Maxn);
    	while (n > 1)
    	{
    		int j, k;
    		for (k = 1; k <= n; ++k)
    			if (v[k - 1] < v[k + 1])
    				break ;
    		for (j = k - 1; j >= 0; --j)
    			if (v[j] > v[k - 1] + v[k])
    				break ;
    		int sum = v[k - 1] + v[k];
    		v.erase(v.begin() + k - 1);
    		v.erase(v.begin() + k - 1);	
    		v.insert(v.begin() + j + 1, sum);
    		ans += sum;
    		--n;
    	}
    	printf("%d\n", ans);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    计算几何

    欧拉公式

    • 在任何一个规则球面地图上,定义 R R R 为区域个数, V V V 为顶点个数, E E E 为边界个数,则恒有:
      R + V − E = 2 R+V-E=2 R+VE=2
    • 推论 凸正多面体有且仅有 5 种。

    证明 取凸正多面体一个顶点,设其向外有 n ( n ≥ 3 ) n(n\ge 3) n(n3) 条棱,再取凸正多面体一个面,设其为正 m ( m ≥ 3 ) m(m\ge 3) m(m3) 边形。一个顶点附近的角之和必须小于 36 0 ∘ 360^\circ 360,则有:
    n ( 180 − 360 m ) < 360 ⇔ 1 − 2 m < 2 n n(180 - \frac{360}{m}) < 360 \Leftrightarrow 1 - \frac{2}{m} < \frac{2}{n} n(180m360)<3601m2<n2
    已知 E = n V 2 = m R 2 E = \frac{nV}{2} =\frac{mR}{2} E=2nV=2mR,代入欧拉公式即可解出 R , E , V R,E,V R,E,V
    符合条件的 m , n m,n m,n 的解只有五组,如下图所示。在这里插入图片描述

    • 设棱长为 a a a,五种凸正多面体的各项数据如下(棱切球即过各边中点的球)。
    正四面体立方体正八面体正十二面体正二十面体
    R R R4681220
    V V V4862012
    E E E612123030
    内切球半径 6 12 a \frac{\sqrt 6}{12}a 126 a 1 2 a \frac{1}{2}a 21a 6 6 a \frac{\sqrt 6}{6}a 66 a 1 2 5 2 + 11 10 5 a \frac{1}{2}\sqrt{\frac{5}{2}+\frac{11}{10}\sqrt 5}a 2125+10115 a 3 3 + 15 12 a \frac{3\sqrt 3 + \sqrt {15}}{12}a 1233 +15 a
    外接球半径 6 4 a \frac{\sqrt 6}{4}a 46 a 3 2 a \frac{\sqrt 3}{2}a 23 a 2 2 a \frac{\sqrt 2}{2}a 22 a 3 4 ( 1 + 5 ) a \frac{\sqrt 3}{4}(1+\sqrt 5)a 43 (1+5 )a 10 + 2 5 4 a \frac{\sqrt{10 + 2\sqrt 5}}{4}a 410+25 a
    棱切球半径 2 4 a \frac{\sqrt 2}{4}a 42 a 2 2 a \frac{\sqrt 2}{2}a 22 a 1 2 a \frac{1}{2}a 21a 3 + 5 4 a \frac{3 + \sqrt 5}{4}a 43+5 a 1 + 5 4 a \frac{1+\sqrt 5}{4}a 41+5 a
  • 相关阅读:
    利用百度AI接口实现车牌识别功能(二)
    Linux中设置git的代理
    Machine Learning Model
    音视频学习笔记——实现PCM和H264合成MP4功能
    Android学习笔记 66. Android Studio 和 Hello World
    量化交易之One Piece篇 - 交易所风控配置文件内容
    青书学堂 看视频 耍课时
    写代码只是皮毛,这才是计算机科学
    Mysql 索引
    计算机竞赛 深度学习人脸表情识别算法 - opencv python 机器视觉
  • 原文地址:https://blog.csdn.net/bzjr_Log_x/article/details/126081867