hihocoder-1142(三分法)

感觉hihocoder和别的OJ有点不一样呢,因为可以看到关于一些常用算法的解释,感觉这个三分法讲的蛮通俗易懂呢:

********************************************************* 下面是引用hihocoder上的讲解 *********************************************************

在之前的几周中我们了解到二分法作为分治中最常见的方法,适用于单调函数,逼近求解某点的值。
但当函数是凸形函数时,二分法就无法适用,这时就需要用到三分法。
从三分法的名字中我们可以猜到,三分法是对于需要逼近的区间做三等分:

我们发现lm这个点比rm要低,那么我们要找的最小点一定在[left,rm]之间。如果最低点在[rm,right]之间,就会出现在rm左右都有比他低的点,这显然是不可能的。 同理,当rm比lm低时,最低点一定在[lm,right]的区间内。
利用这个性质,我们就可以在缩小区间的同时向目标点逼近,从而得到极值。

********************************************************* 上面是引用hihocoder上的讲解 *********************************************************

对于1142这个题目,通过在画图我们可以看到,距离给定点P(xp, yp)最近的二次曲线上的点Q,可能有5两种情况:

(1)点在碗左侧

(2)点在碗右侧

(3)点在碗里且在对称轴左侧

(4)点在碗里且在对称轴右侧

(5)点在碗里且在对称轴上

假设中心线和抛物线的交点为M(xm, ym),则进一步还可以看到,(1)和(3)的情况极值点所在的区间都是(-∞,xm),而(2)和(4)的情况极值点所在的区间都是(xm,+∞),需要注意的是点P在对称轴上的情况,当P点yp和M点的ym很近时,最近的点即是M,而yp和ym相距较远时,距离P点最近的点不再时M,而是在抛物线左半边和右半边各有一个。

另外还有几个细节需要注意:

(1)当点在曲线上时,要输出“0.000”而不是单个的"0"

(2)题目要求输出的是最近点的距离且距离精确到小数点后第三位,但是在三分的时候我们分的仍然是x坐标的区间,需要注意判断结束的条件。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

class Quadratic{
private:
	double a, b, c;
public:
	Quadratic(double aa, double bb, double cc) : a(aa), b(bb), c(cc){}
	double operator()(double x){
		return a*x*x + b*x + c;
	}
};
class DistanceXY{
private:
	double x0, y0;
	Quadratic fun;
public:
	DistanceXY(double a, double b, double c, double x, double y) : x0(x), y0(y), fun(a, b, c){}
	double operator()(double x){
		return sqrt(pow(x0 - x, 2) + pow(fun(x) - y0, 2));
	}
};

double minPeak(double l, double r, double esp, DistanceXY fun)
{
	double lm, rm, d;
	while(r - l >= esp || fabs(fun(r) - fun(l)) >= esp){
		d = (r - l) / 3;
		lm = l + d;
		rm = r - d;
		if(fun(lm) < fun(rm)) r = rm;
		else l = lm;
	}
	return fun(l);
}

int main()
{
	int a, b, c, x, y;
	double p;

	scanf("%d%d%d%d%d", &a, &b, &c, &x, &y);
	if(a*x*x + b*x + c == y) puts("0.000");
	else{
		p = -0.5 * b / a;
		if(x < p) printf("%.3f\n", minPeak(-300, p, 1e-3, DistanceXY(a, b, c, x, y)));
		else if(x > p) printf("%.3f\n", minPeak(p, 300, 1e-3, DistanceXY(a, b, c, x, y)));
		else{
			double d = fabs(b * b * -0.25 / a + c - y);
			printf("%.3f\n", min(d, minPeak(p, 300, 1e-3, DistanceXY(a, b, c, x, y))));
		}
	}

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值