hihocoder 1142 三分法求极值

题目链接

  思路:

直接一个裸的三分,第一次接触三分 就此机会学习一下,三分的复杂度也是log级别的.

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

hihocoder 1142 三分法求极值_第1张图片

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

接下来我们回到题目上,抛物线和点之间的距离可以简单的用直线公式计算:
即d = min{sqrt((X - x)^2+(aX^2+bX+c-y)^2)}
该公式展开后为4次,需要采用求导等方法来求极值。对于计算机编程来说是很麻烦的一件事。

进一步观察题目,我们可以发现根据带入的X值不同,d的长度恰好满足凸形函数。
而我们要求的最短距离d,正好就是这个凸形函数的极值。
那么三分法不就正好可以用来解决这道题目了么?

需要注意在解题过程中一定要想清楚如何划分区间,我们求的各个变量到底是什么含义。
另外,这道题还有一个小小的trick,在解决的时候请一定要小心。

ps:

这种题目就得注意精度啊.....

#include
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 100000007
#define exp 0.00000001
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int a,b,c,x,y;
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}
double check(double xx)
{
	double yy=a*xx*xx+b*xx+c;
	return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
}
int main()
{
	Ri(a),Ri(b),Ri(c),Ri(x),Ri(y);
	double l=-200,r=200,mid,mmid;
	while(l+exp=check(mmid))
			l=mid;
		else
			r=mmid;
	}
	printf("%.3lf\n",check(l));
	return 0;
}


你可能感兴趣的:(三分)