算法导论——精选推荐
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法导论
说明
对于算法基础的⼀个补充
矩形求交并
等效到线段的交并上,注意这⾥把矩形表⽰调整为左下⾓ + 右上⾓
static const rectangle empty_tuple = make_tuple(INT64_MAX,INT64_MAX,INT64_MAX,INT64_MAX);
tuple<ll,ll,ll,ll> get_insec(tuple<ll,ll,ll,ll> a,tuple<ll,ll,ll,ll> b)
{
if (a == empty_tuple or b == empty_tuple)
return empty_tuple;
ll x1,y1,x2,y2;
ll x3,y3,x4,y4;
std::tie(x1,y1,x2,y2) = a;
std::tie(x3,y3,x4,y4) = b;
if (x1 > x2)
swap(x1,x2);
if (y1 > y2)
swap(y1,y2);
if (x3 > x4)
swap(x3,x4);
if (y3 > y4)
swap(y3,y4);
if (x4 < x1 or x2 < x3)
return empty_tuple;
if (y4 < y1 or y2 < y3)
return empty_tuple;
return make_tuple(max(x1,x3),max(y1,y3),min(x2,x4),min(y2,y4));
}
RSA加密
前置知识
欧拉定理
若gcd(a,n) = 1,那么
a^{\phi(n)} = 1 (mod n)
RSA算法
任选两个不同的⼤质数p = 61,q = 53
从[1,\phi(p * q) - 1]中任选两个数e = 17,d = 2753,使得e * d = 1 \quad (mod \quad \phi(p * q))
销毁p,q
其中,(p * q,e) = (3233,17)是公钥匙,(p * q,d)= (3233,2753)是私钥
实际应⽤中公钥和私钥都是采⽤ASN.1格式表达的
加密操作
假设需要加密的消息为m(必须是整数,并且 < n)
密⽂ = m^e % n = 65^{17} = 2790 (mod 3233)
解密操作
假设需要解密的消息为c
原⽂ = c^d = m % n = 2790^2753 = 65 (mod 3233)
单纯型算法
pivot操作的复杂度显然是O(NM)的,但是最优化操作中pivot操作的调⽤次数可能会成为指数级。
但是我们可以发现要达到这个指数级的调⽤次数,边权也必须是指数级的。
所以在OI中往往跑得⽐谁都快。
所以“能在1s内跑出范围为⼏百的数据”。
椭球算法 O(n^6 * m^{2})
内点算法O(n^{3.5}*m^{2})
改进的内点算法O(n^{3.5}*m)
标准型
松弛型
基本性质和操作
1.解空间是⼀个凸区域或者⽆界区域
2.总在凸区域的顶点取得最值
单纯型算法步骤
确定基本可⾏解(在⼤部分情况中简单的把所有变量取0即可)
在最⼤化函数中,选择⼀个系数不为负数的变量x_k
当x_k增⼤时,确定其他变量对x_k增长的约束(因为要求所有变量⾮负)
如果所有的约束都是⽆穷⼤,那么返回⽆界
并选择其中⼀个对x_k约束最紧的变量x_j
转轴(x_k,x_j)
不停的做上述操作,直到最⼤化函数的所有变量系数都为负,此时得到单纯型的解
算法导论证明了,每次迭代都不会减少最⼤化函数的值,但是,存在使得最⼤化值不变的情况称之为退化
如果⼀个单纯型执⾏超过c(n + m,m)次的迭代,那么它就是循环的
可以在simplex中通过选择最⼩下标的变量,保证单纯型算法⼀定会终⽌
或者微扰变量,或者按照字典序打破⼀样的⽬标值,都可以打破循环
如何取得基本可⾏解,当变量全取0时,存在⾮负系数如何处理
转轴操作pivot
选择⼀个基变量x_B(换出变量)以及⼀个⾮基变量x_N(换⼊变量)将其互换
simplex(单纯型算法的主要操作)
即从⼀个基本解出发,经过⼀系列转轴操作,抵达最优点。
通过选择特定的换⼊和换出变量,可以使得每⼀次转轴操作都能使⽬标函数增⼤,直到达到全局最优解
主定理
⽤来计算T(n) = aT(\frac{n}{b}) + f(n)的上界
1.若存在常数ε > 0,有f(n) = O(n^{log_{b}{(a)} - ε}),则T(n) = \Theta (n^{log_b{a}})
2.若f(n) = O(n^{log_{b}{(a)}}),则T(n) = \Theta (n^{log_b{a}} log(n))
3.若存在常数ε > 0,有f(n) = O(n^{log_{b}{(a)} + ε}),且对常数c < 1与⾜够⼤的n,有af(n) \leq cf(n),则T(n) = \Theta (f(n))
摊还分析
1.聚合分析
给每个操作赋值⼀个费⽤(这⾥赋值为该操作的真实费⽤)
构造⼀个操作序列,使得它的运⾏复杂度最坏,记此时的复杂度为T(n)
那么T(n)显然就是该算法的最坏的真实复杂度上界
该⽅法的缺点是真实的计算⼀般很困难、复杂
2.会计分析
给每个操作赋值⼀个费⽤(这⾥赋值为该操作的摊还费⽤,可正可负)
对于任意的操作序列,使它的运⾏后
\sum{(操作次数) * (摊还代价)} \geq 0
此时\max\{\sum{[摊还代价 > 0](操作次数) * (摊还代价)} \}就是该算法的摊还上界
会计分析相当于是聚合分析的⼀个改进,避开了聚合分析时,分析真实操作时⾮常困难的弊端
3.势函数
和会计分析等价,区别在于会计分析是先验的,也就是你需要预先给每个操作赋值费⽤
⾸先定义势能函数,和初始势能(⼀般定义为0),并且要求,势能在任意操作下不能为负
然后计算,某个操作的摊还代价 = 真实代价 + 势能变化
然后计算在最坏操作序列下的摊还代价
注意,每个操作的费⽤是我们通过势函数 + 真实代价计算出来的
并且随着势函数的不同,计算出来的单个操作的摊还代价是不同的
最后强调⼀下,设计势函数\rightarrow 计算每个操作的摊还代价 \rightarrow 计算总的摊还代价 \rightarrow 得到复杂度上界
势能法分析hash表
定义
size[n] = 第n次操作时总的槽数
num[n] = 第n次操作时表中的对象数量
\alpha = 装载率
只插⼊,当\alpha > \frac{1}{2}时扩张(扩张复杂度为O(num[n - 1] + 1))
定义势函数\psi(T) = 2 * num[T] - size[T],于是有\psi(0) = 0,且势永不为负
若第i次操作没有触发表扩张,则
则num[i] = num[i - 1] + 1,size[i] = size[i - 1]
摊还代价 = 真实代价 + 势能变化 = 1 + (2 * num[i] - size[i]) - (2 * num[i - 1] - size[i - 1])
化简得摊还代价 = 3
若第i次操作触发了表扩张
则num[i] = size[i - 1] + 1 = num[i - 1] + 1,size[i] = size[i - 1] * 2
摊还代价 = 真实代价 + 势能变化 = num[i - 1] + 1 + (2 * num[i] - size[i]) - (2 * num[i - 1] - size[i - 1])
化简得摊还代价 = 3
综上所述,摊还代价为O(3 * n) = O(n)
我悟了,⾮常妙
插⼊ + 删除,删除时可能表收缩,使得\alpha <= \frac{1}{2}
定义势函数
\psi(T)=\left\{ \begin{array}{rcl} 2 * num[T] - size[T] & & {\alpha \geq \frac{1}{2}}\\ \frac{size[T]}{2} - num[T] & & \alpha < \frac{1}{2} \end{array} \right.
只分析⼀下第i次delete引起了表收缩,其余同上
收缩时,摊还代价 = 实际代价 + 势能变化 = 1 + num[i] + (\frac{size[i]}{2} - num[i]) - (\frac{size[i - 1]}{2} - num[i - 1])
化简得摊还代价= 3
Processing math: 0%。