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

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