【专题】三分法和牛顿迭代法总结

来源:互联网 发布:linux配置网关命令 编辑:程序博客网 时间:2024/06/05 04:15

下面总结两种迭代方法:三分法和牛顿迭代

1.三分法

二分法作为分治中最常见的方法,适用于单调函数,逼近求解某点的值。但当函数是凸性函数时,二分法就无法适用,这时三分法就可以大显身手。 如下凸函数:

迭代逼近.jpg

类似二分的定义left和right

mid1 = (left + right) / 2mid2 = (mid2 + right) / 2如果mid1靠近极值点, left = mid1如果mid2靠近极值点, right = mid2

三分的原理就是每次搜索去掉2/3

程序模版如下:


double Calc(Type a){    /* 根据题目的意思计算 */}void Solve(void){    double Left, Right;    double mid, midmid;    double mid_value, midmid_value;    Left = MIN; Right = MAX;    while (Left + EPS < Right)    {        mid = (Left + Right) / 2;        midmid = (mid + Right) / 2;        mid_area = Calc(mid);        midmid_area = Calc(midmid);        // 假设求解最大极值.        if (mid_area >= midmid_area) Right= midmid;        else Left = mid;    }}

2.牛顿迭代

牛顿迭代法又称为牛顿-拉夫逊方法(Newton-Raphsonmethod),是一种在实数域和复数域上通过迭代计算求出非线性方程的数值解方法。方法的基本思路是利用一个根的猜测值x0做初始近似值,使用函数f(x)在x0处的泰勒级数展式的前两项做为函数f(x)的近似表达式。由于该表达式是一个线性函数,通过线性表达式替代方程f(x) = 0中的f(x)求得近似解x1。即将方程f(x) = 0在x0处局部线性化计算出近似解x1,重复这一过程,将方程f(x) = 0在x1处局部线性化计算出x2,求得近似解x2,……。

牛顿迭代法的最大优点是收敛速度快,具有二阶收敛。以著名的平方根算法为例,说明二阶收敛速度的意义

例题分析

poj 3301 Texas Trip

题目大意

给出平面中的点集,求可以覆盖这些点的最小面积正方形。

题目分析

问题是要求最小的正方形,假设这个正方形的边都是分别与坐标轴平行,也就是说正方形没有旋转一定的角度,那么我们只要考虑最上,最下,最左,最右 的点即可,当正方形旋转过一定的角度d是我们也只要考虑最边上的点的距离差即可(故这题也可用枚举旋转角度的方法来求解,但要注意步长的选取以保证精度)。

假设旋转角度为d,那么枚举每两个点关于旋转角度为d的直线距离取最大值,即可保证覆盖所有的点,在两个方向上这样的距离分别为:

  dis1 = fabs(cos(d) * (y[i] - y[j]) - sin(d) * (x[i] - x[j]))  dis2 = fabs(sin(d) * (y[i] - y[j]) + cos(d) * (x[i] - x[j]))

以上式子很好推导,自己画出坐标系,分析即可。

当然dis1和dis2大小不一定一致,要保证图形是覆盖所有点的正方形,所以我们选取较大者为边长。

精度问题:解决这个问题可以迭代M次,每次迭代把上一次得到的最优值附近再分为N份,重新旋转求最优值。取N=1000, M=10即可获得精确值。

题目源码

//在0-90度范围内三分旋转的角度  //旋转公式:x’=x*cos(phi)-y*sin(phi)    y’=x*sin(phi)+y*cos(phi)  #include<iostream>  #include<cstdio>  #include<cmath>  using namespace std;  struct point  {     double x,y;  }p[31];  int n;  const double pi=acos(-1.0);  const double eps=1e-4;  double area(double a)  {     return a*a;  }  double max(double a,double b)  {     return a>b?a:b;  }  double cal(double z)  {     int i;     double x,y;     double max_x=-10000.0,max_y=-10000.0,min_x=10000.0,min_y=10000.0;     for(i=0;i<n;i++)     {         x=p[i].x*cos(z)-p[i].y*sin(z);         y=p[i].x*sin(z)+p[i].y*cos(z);         if(max_x<x)             max_x=x;         if(max_y<y)             max_y=y;         if(min_x>x)             min_x=x;         if(min_y>y)             min_y=y;     }     return max(area(max_x-min_x),area(max_y-min_y));  }  double div()  {     double left=0,right=pi/2.0;     double ans1,ans2;     double m,mm;     do     {         m=(left+right)/2.0;         mm=(right+m)/2.0;         ans1=cal(m);         ans2=cal(mm);         if(ans1<ans2)             right=mm;         else             left=m;     }while(fabs(ans1-ans2)>eps);     return ans1;  }  int main()  {     int t;     scanf("%d",&t);     while(t--)     {         scanf("%d",&n);         int i;         for(i=0;i<n;i++)             scanf("%lf%lf",&p[i].x,&p[i].y);         printf("%.2lf\n",div());     }     return 0;  }  

题目推荐

现根据几道的OJ题目来分析三分法的具体实现。

buaa 1033 Easy Problem
http://acm.buaa.edu.cn/oj/problem_show.php?c=0&p=1033

题意为在一条线段上找到一点,与给定的P点距离最小。很明显的凸性函数,用三分法来解决。
Calc函数即为求某点到P点的距离。

ZOJ 3203 Light Bulb
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3203


如图,人左右走动,求影子L的最长长度。
根据图,很容易发现当灯,人的头部和墙角成一条直线时(假设此时人站在A点),此时的长度是影子全在地上的最长长度。当人再向右走时,影子开始投影到墙上,当人贴着墙,影子长度即为人的高度。所以当人从A点走到墙,函数是先递增再递减,为凸性函数,所以我们可以用三分法来求解。

下面只给出Calc函数,其他直接套模版即可。
double Calc(double x)
{
    return (h * D - H * x) / (D - x) + x;
}

heru 5081 Turn the corner 08年哈尔滨regional网络赛
http://acm.hrbeu.edu.cn/index.php?act=problem&id=1280


汽车拐弯问题,给定X, Y, l, d判断是否能够拐弯。首先当X或者Y小于d,那么一定不能。
其次我们发现随着角度θ的增大,最大高度h先增长后减小,即为凸性函数,可以用三分法来求解。

这里的Calc函数需要比较繁琐的推倒公式:
s = l * cos(θ) + w * sin(θ) - x;
h = s * tan(θ) + w * cos(θ);
其中s为汽车最右边的点离拐角的水平距离, h为里拐点最高的距离, θ范围从0到90。

POJ 3301 Texas Trip
http://acm.pku.edu.cn/JudgeOnline/problem?id=3301

题意为给定n(n <= 30)个点,求出饱含这些点的面积最小的正方形。

有两种解法,一种为逼近法,就是每次m分角度,求出最符合的角度,再继续m分,如此进行times次,即可求出较为精确的解。(m 大概取10, times取30即可)

第二种解法即为三分法,首先旋转的角度只要在0到180度即可,超过180度跟前面的相同的。坐标轴旋转后,坐标变换为:
X’ = x * cosa - y * sina;
y’ = y * cosa + x * sina;

hdu 3400 Line belt
http://acm.hdu.edu.cn/showproblem.php?pid=3400
典型的三分法,先三分第一条线段,找到一个点,然后根据这个点再三分第二条线段即可,想出三分的思路基本就可以过了。

对于求解一些实际问题,当公式难以推导出来时,二分、三分法可以较为精确地求解出一些临界值,且效率也是令人满意的。




这里的Calc函数需要比较繁琐的推倒公式:
s = l * cos(θ) + w * sin(θ) - x;
h = s * tan(θ) + w * cos(θ);
其中s为汽车最右边的点离拐角的水平距离, h为里拐点最高的距离, θ范围从0到90。
POJ 3301 Texas Trip
http://acm.pku.edu.cn/JudgeOnline/problem?id=3301


题意为给定n(n <= 30)个点,求出饱含这些点的面积最小的正方形。


有两种解法,一种为逼近法,就是每次m分角度,求出最符合的角度,再继续m分,如此进行times次,即可求出较为精确的解。(m 大概取10, times取30即可)


第二种解法即为三分法,首先旋转的角度只要在0到180度即可,超过180度跟前面的相同的。坐标轴旋转后,坐标变换为:
X’ = x * cosa - y * sina;
y’ = y * cosa + x * sina;


hdu 3400 Line belt
http://acm.hdu.edu.cn/showproblem.php?pid=3400
典型的三分法,先三分第一条线段,找到一个点,然后根据这个点再三分第二条线段即可,想出三分的思路基本就可以过了。
对于求解一些实际问题,当公式难以推导出来时,二分、三分法可以较为精确地求解出一些临界值,且效率也是令人满意的。


三分法buaa 1024buaa 1033 Easy Problem zoj  3203 Light Bulbhdoj 3400 Line belthdoj 2438 turn the corner牛顿迭代poj 1905 Expanding Rodspoj 3122 Piepoj 2728 Desert Kingpoj 2868 Computer DJpoj 3727 Newton’s Method

原创粉丝点击