分治法
概念
分治法,字面意思是“分而治之”,就是把一个复杂的1问题分成两个或多个相同或相似的子问题,再把子问题分成更小的子问题直到最后子问题可以简单地直接求解,
原问题的解即子问题的解的合并,这个思想是很多高效算法的基础,例如排序算法(快速排序,归并排序),傅里叶变换(快速傅里叶变换)等。、
百度百科:
采用分治法解决的问题一般具有的特征如下:
1. 问题的规模缩小到一定的规模就可以较容易地解决。
2. 问题可以分解为若干个规模较小的模式相同的子问题,即该问题具有最优子结构性质。
3. 合并问题分解出的子问题的解可以得到问题的解。
4. 问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题。
1. 划分步:把输入的问题划分为k个子问题,并尽量使这k个子问题的规模大致相同。
2. 治理步:当问题的规模大于某个预定的阈值n0时,治理步由k个递归调用组成。
3. 组合步:组合步把各个子问题的解组合起来,它对分治算法的实际性能至关重要,算法的有效性很大地依赖于组合步的实现。
分治法的关键是算法的组合步。究竟应该怎样合并,没有统一的模式,因此需要对具体问题进行具体分析,以得出比较好的合并算法。
例一:归并排序
例二:二分搜索
老方法了
m=(l+r)/2的
要求是有序的序列里
案例一:
题意:
给一个字典:
若干个:
英语 外语
…
之后一个空行
之后找若干个外文对应的英文,找不到写eh
外文
…
范围:
每一个单词不超过10个字母
最多有1e5条目
最多找1e5个
要点一:二分搜索
暴力是肯定要超时的
1e11了
——strcmp是o(n)
优化,可用二分查找,不是一个一个找
弄一个cmp函数
或者重载
开始先sort把字典排好序
要点二:识别空行
自定义判断:
gets(s);
if(s[0]!=0)//不是空行
sscanf(s,"%s","%s");
——用gets()和sscanf()
案例二:交叉的梯子
题意:
一个狭窄的街道两旁都是高楼。一个x英尺长的梯子,抵在街道右侧的高楼,靠在左边的高楼;一个y英尺长的梯子,抵在街道左侧的高楼,靠在右边的高楼。两个梯子交叉,交叉点离地面c英尺。这条街有多宽?
三分法求极值
不妨求最大值
x轴上l到r区间
取三等分点a,b
l到a,a到b,b到r
参考
注意:连续可求极值,凹凸性不变的函数求最值
二分法求根
数学有学
注意:由介值定理,连续一定能有解,单调可得唯一解
此处透镜公式
公式推导:
设x梯子高为a,y梯子高为b,底边为d; 则:c/a = d1/d, c/b = d2/d; 因d1 + d2 = d,故c/a + c/b
= 1;
案例三:快速幂,求ab%c
复习复习,要忘了
基础:
(a+b)%m=a%m+b%m
a*b%m=(a%m)*(b%m)
a^b%m=(a%m)^b
——取模随时可以进行
把b用二进制表示
算了符号太多打不出来了www,qwq
案例四:矩阵快速幂求斐波那契
那个斐波那契与线性代数矩阵的关系拍案叫绝,老师也讲了
HOJ,要校园网
求后四位
矩阵快速幂的结果,每次模10000
求前四位
公式:
那个数乘10000即可知
——如果n还小,不能忽略后者。可以前四十个直接算
代码中传二维数组:
void mul(int a[2][2],int b[2][2],int c[2][2]);//因为是指针了,不要再引用也不用再传指针
int a[2][2],b[2][2],c[2][2];
mul(a,b,c);
输出小心:补0
最后四位,补0,否则莫名其妙WA。
一般线性递推关系的A矩阵:
a[n]=c[1]*a[n-1]+c[2]*a[n-2]+...+c[k]*a[n-k]
有矩阵:
1 0 0 ... 0
0 1 0 ... 0
.
.
0 0 0 ... 1
c1 c2 c3...cn
它的n次方左乘
a0
a1
.
.
ak-1
是
an
an+1
.
.
an+k+1