三分求最小值——HDU3400
阿新 • • 發佈:2019-02-05
題目連結:
題目大意:
給定兩條線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; }