三分法 for 单峰函数[数值计算][题目sgu 114, zoj 3421]

三分法 for 单峰函数[数值计算][题目sgu 114, zoj 3421]

(好多地方其实画图比较好,奈何linux的各种画图工具用着不舒服。。又不愿意用opengl什么的画图,那么各位看官就锻炼一下自己的yy能力吧~)
所谓单调函数二分法,单峰函数三分法。

单调函数二分法,函数在给定定义域内单调,可以根据单调性来二分逼近答案。
单峰函数三分法,函数在给定定义域内有不超过一个的峰值,可以根据其单峰特性来三分逼近答案。

只说三分:
迭代到当前轮:
迭代的当前区间[l,r],区间长度为d=r-l,那么三分点为m1=l+d,m2=r-d。4点三等分区间,这样保证每次迭代后,新区间变为原区间的2/3;如果用1/2,3/4分点的话,迭代后有可能变为原来的3/4,这样比较慢。log1.25(n)毕竟比log1.3333(n)要大啊~
设目标函数是f(x),比较f(m1) , f(m2),如果f(m1)比f(m2)更趋近峰值,那么就让r=m2,即右端点左移;反之左端点右移。仔细想想就是,如果左边更靠近峰值的话,那么肯定让右侧向左侧移动;反之亦然。
伪码:
while(l < r)//dblcmp is preferred
{
d = (r - l) / 3;
m1 = l +d;
m2 = m1 +d;
if(f(m1) better than f(m2))
r = m2;
else
l = m1;
}
l or r is the solution

下面谈到具体问题:
sgu 114, 题目大意就不说了,自己看去,抽象出来的方程就是。
f(x) = sum{|x-y[i]| * p[i]},i = 1 to n
ans = min(f(x)) 其中y[i]、p[i]给定
这题做法很多,求中位数、分段二分、三分皆可做;
说一下思路吧:
仔细观察发现,这是一个分段单调的函数。
以x为自变量会发现,在每一个分段内,f(x) = f(floor(x)) + (sum{p[i]}(小于x的每个i} - sum{p[i]}(大于x的每个i)) * (x - floor(x))
其中含有sum的那部分就是每个分段的不同点:斜率或者说单调性;可以发现这个单调性是随着x的增长(分段),不断下降的,从单调降逐渐过度到单调升(如果存在这两个过程的话)。
所以此函数单峰。。其他的就不用多说了。

zoj 3421,10年成都现场赛F题,印象深刻啊,想当年不知道单峰函数可以三分,不然没准就可以拿到silver了。。

一堆a>=0的二次函数Si(x),f(x) = max(Si(x)),求在x belongs to [0,1000]内的min(f(x))
稍微画一下图便可以看出来,f(x)的图像是一个单峰的函数,根据所有的Si(x)a>=0也可以看出来,f(x)的函数值越靠近两侧应该越大,靠近中间应该越低,所以出现了谷(反着的峰哈。。)。。。然后三分之。。。
精度要求挺高,输出1e-4,而eps到1e-8竟然还不够,需要1e-10。。。
另外,输出的是f(ans),不是ans。。。坑死我了,10多炮wa啊。。。
代码什么的就不attach了。
以上。。三分什么的,也是折半思想一种典型应用。欢迎吐槽+拍砖。

你可能感兴趣的:(三分法 for 单峰函数[数值计算][题目sgu 114, zoj 3421])