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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章