1. 程式人生 > >三分求最小值——HDU3400

三分求最小值——HDU3400

題目連結:

題目大意:

給定兩條線AB和CD,現在要從A點,走到D點。

線上段上AB上走,速度是p,線上段CD,上走速度是q,在空間中其他地方走速度是r。

求所需的最小時間。

解題思路:

線上段AB上,任取一點E,A-E-CD的時間必定是一個關於點E的凹函式。

那麼我們可以通過三分列舉AB上面的點求取E點,進而求取最小時間。

當AB上的E點固定的時候,求取A-E-CD的最小時間同樣可以在CD上面三分列舉求取最小時間。

所以這個題目就是三分裡面巢狀三分,具體實現見原始碼。

網上說的精度什麼的,個人感覺是不可信的,這個題目資料有點水。

如果將我的程式碼的精度改成10的-1次方還是可以AC。

不過需要注意一些特殊情況還有初始化,因為有可能A B點重合或者是C D點重合。

原始碼:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const double eps=1e-5;
double P,Q,R;
struct node
{
    double x,y;
};
node l1,r1,l2,r2;

double dis(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double cal(node a,node b)
{
    return dis(l1,a)/P+dis(b,r2)/Q+dis(a,b)/R;
}

double time(node a)     //在AB上面確定一個點a,用三分的方法求取A——a——CD的最小時間
{
    node l,r;
    node p1,p2;
    l.x=l2.x; l.y=l2.y;
    r.x=r2.x; r.y=r2.y;
    while(dis(r,l)>eps)
    {
        p1.x=l.x+(r.x-l.x)*0.382;
        p1.y=l.y+(r.y-l.y)*0.382;
        p2.x=l.x+(r.x-l.x)*0.618;
        p2.y=l.y+(r.y-l.y)*0.618;

        if(cal(a,p1)>cal(a,p2))
        {
            l.x=p1.x;   l.y=p1.y;
        }
        else
        {
            r.x=p2.x;   r.y=p2.y;
        }
    }
    return min(cal(a,l),cal(a,r));
}
int main()
{
	//freopen("in.txt","r",stdin);
	int cs;
	node l,r;
	node p1,p2;
	scanf("%d",&cs);
	while(cs--)
	{
	    scanf("%lf%lf%lf%lf",&l1.x,&l1.y,&r1.x,&r1.y);
	    scanf("%lf%lf%lf%lf",&l2.x,&l2.y,&r2.x,&r2.y);

	    scanf("%lf%lf%lf",&P,&Q,&R);
	    l.x=l1.x;    l.y=l1.y;
	    r.x=r1.x;    r.y=r1.y;
	    while(dis(l,r)>eps)
	    {
	        p1.x=l.x+(r.x-l.x)*0.382;
	        p1.y=l.y+(r.y-l.y)*0.382;
	        p2.x=l.x+(r.x-l.x)*0.618;
	        p2.y=l.y+(r.y-l.y)*0.618;

	        if(time(p1)>time(p2))
	        {
	            l.x=p1.x;   l.y=p1.y;
	        }
            else
            {
                r.x=p2.x;   r.y=p2.y;
            }
	    }
	    printf("%.2lf\n",min(time(l),time(r)));
	}
	return 0;
}