﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-From A Start,As An Acmer-随笔分类-计算数学</title><link>http://www.cppblog.com/aswmtjdsj/category/18670.html</link><description>My Way to Final</description><language>zh-cn</language><lastBuildDate>Thu, 31 May 2012 19:05:00 GMT</lastBuildDate><pubDate>Thu, 31 May 2012 19:05:00 GMT</pubDate><ttl>60</ttl><item><title>三分法 for 单峰函数[数值计算][题目sgu 114, zoj 3421]</title><link>http://www.cppblog.com/aswmtjdsj/archive/2012/02/20/166058.html</link><dc:creator>BUPT-[aswmtjdsj] @ Penalty</dc:creator><author>BUPT-[aswmtjdsj] @ Penalty</author><pubDate>Mon, 20 Feb 2012 05:22:00 GMT</pubDate><guid>http://www.cppblog.com/aswmtjdsj/archive/2012/02/20/166058.html</guid><wfw:comment>http://www.cppblog.com/aswmtjdsj/comments/166058.html</wfw:comment><comments>http://www.cppblog.com/aswmtjdsj/archive/2012/02/20/166058.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/aswmtjdsj/comments/commentRss/166058.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/aswmtjdsj/services/trackbacks/166058.html</trackback:ping><description><![CDATA[（好多地方其实画图比较好，奈何linux的各种画图工具用着不舒服。。又不愿意用opengl什么的画图，那么各位看官就锻炼一下自己的yy能力吧～）<br />所谓单调函数二分法，单峰函数三分法。<br /><br />单调函数二分法，函数在给定定义域内单调，可以根据单调性来二分逼近答案。<br />单峰函数三分法，函数在给定定义域内有不超过一个的峰值，可以根据其单峰特性来三分逼近答案。<br /><br />只说三分：<br />迭代到当前轮：<br />迭代的当前区间[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)要大啊～<br />设目标函数是f(x)，比较f(m1) , f(m2)，如果f(m1)比f(m2)更趋近峰值，那么就让r=m2,即右端点左移；反之左端点右移。仔细想想就是，如果左边更靠近峰值的话，那么肯定让右侧向左侧移动；反之亦然。<br />伪码：<br />while(l &lt; r)//dblcmp is preferred<br />{<br />d = (r - l) / 3;<br />m1 = l +d;<br />m2 = m1 +d;<br />if(f(m1) better than f(m2))<br />r = m2;<br />else<br />l = m1;<br />}<br />l or r is the solution<br /><br />下面谈到具体问题：<br />sgu 114, 题目大意就不说了，自己看去，抽象出来的方程就是。<br />f(x) = sum{|x-y[i]| * p[i]},i = 1 to n<br />ans = min(f(x)) 其中y[i]、p[i]给定<br />这题做法很多，求中位数、分段二分、三分皆可做；<br />说一下思路吧：<br />仔细观察发现，这是一个分段单调的函数。<br />以ｘ为自变量会发现，在每一个分段内，f(x) = f(floor(x)) + (sum{p[i]}(小于x的每个ｉ} - sum{p[i]}(大于x的每个i)) * (x - floor(x))<br />其中含有sum的那部分就是每个分段的不同点：斜率或者说单调性；可以发现这个单调性是随着x的增长（分段），不断下降的，从单调降逐渐过度到单调升（如果存在这两个过程的话）。<br />所以此函数单峰。。其他的就不用多说了。<br /><br />zoj 3421,10年成都现场赛F题，印象深刻啊，想当年不知道单峰函数可以三分，不然没准就可以拿到silver了。。<br /><br />一堆a&gt;=0的二次函数Si(x)，f(x) = max(Si(x))，求在x belongs to [0,1000]内的min(f(x))<br />稍微画一下图便可以看出来，f(x)的图像是一个单峰的函数，根据所有的Si(x)a&gt;=0也可以看出来，f(x)的函数值越靠近两侧应该越大，靠近中间应该越低，所以出现了谷（反着的峰哈。。）。。。然后三分之。。。<br />精度要求挺高，输出1e-4,而eps到1e-8竟然还不够，需要1e-10。。。<br />另外，输出的是f(ans)，不是ans。。。坑死我了，10多炮wa啊。。。<br />代码什么的就不attach了。<br />以上。。三分什么的，也是折半思想一种典型应用。欢迎吐槽+拍砖。<img src ="http://www.cppblog.com/aswmtjdsj/aggbug/166058.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/aswmtjdsj/" target="_blank">BUPT-[aswmtjdsj] @ Penalty</a> 2012-02-20 13:22 <a href="http://www.cppblog.com/aswmtjdsj/archive/2012/02/20/166058.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>