学完二分查找之后, 再学三分搜索之后确实好很多,而且概念也比较容易理解,但是在实际的问题中用起来还是十分不顺手。费了好半天的劲才把hdu的代码敲下来。
三分的主要思想:
如上图所示,类似二分的定义,mid =(left + right)/ 2,midmid = (mid + right)/ 2,如果mid靠近极值点,则right = midmid,否则left = mid。
模板如下:
double Calc(Type a)
{
/* 根据题目的意思计算 */
}
void Solve()
{
double left, right;
double mid, midmid;
double mid_value, midmid_value;
left = MIN; right = MAX;
while (left + EPS < right)
{
mid = (left + right) / 2;
midmid = (mid + right) / 2;
三分搜索法的模板如下:
double Calc(Type a)
{
/* 根据题目的意思计算 */
}
void Solve()
{
double left, right;
double mid, midmid;
double mid_value, midmid_value;
left = MIN; right = MAX;
while (left + EPS < right)
{
mid = (left + right) / 2;
midmid = (mid + right) / 2;
mid_value = Calc(mid);
midmid_value = Calc(midmid);
// 假设求解最大极值.
if (mid_ value >= midmid_ value) right = midmid;
else left = mid;
}
}
看完之后参照学姐的讲课做了一道三分的题目,hdu3400:http://acm.hdu.edu.cn/showproblem.php?pid=3400
这道题的解题思路思路就是:题目要求我们找到A点到D点的最短时间,所以我们需要在AB线段上找一点p1,CD上面找一点p2,这里我们就可以用三分的思想来找。总时间就是在Ap1上面花的时间+p1p2上面花时间+p2D上面花的时间。
代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define EPS 1e-8
using namespace std;
double p, q, r;
struct point
{
double x;
double y;
} A,B,C,D;
double dist(point a, point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dist_cd(point p1, double m)
{
point p2;
p2.x = C.x + (D.x-C.x)*m;
p2.y = C.y + (D.y-C.y)*m;
return (dist(D, p2)/q + dist(p1, p2)/r);
}
double time_cd(point p1)
{
double mid, midmid, mid_value, midmid_value;
double left = 0.0, right = 1.0;
while(left+EPS<right)
{
mid = (left+right)/2;
midmid = (mid+right)/2;
mid_value = dist_cd(p1, mid);
midmid_value = dist_cd(p1, midmid);
if(mid_value<midmid_value) right = midmid;
else left = mid;
}
return dist_cd(p1, left);
}
double dist_ab(double m)
{
point p1;
p1.x = A.x+(B.x-A.x)*m;
p1.y = A.y+(B.y-A.y)*m;
return (dist(A, p1)/p + time_cd(p1));
}
double time_ab()
{
double mid, midmid, mid_value, midmid_value;
double left = 0.0, right = 1.0;
while(left+EPS < right)
{
mid = (left+right)/2;
midmid = (mid+right)/2;
mid_value = dist_ab(mid);
midmid_value = dist_ab(midmid);
if(mid_value<midmid_value) right = midmid;
else left = mid;
}
return dist_ab(left);
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
{
scanf("%llf%llf%llf%llf", &A.x, &A.y, &B.x, &B.y);
scanf("%llf%llf%llf%llf", &C.x, &C.y, &D.x, &D.y);
scanf("%llf%llf%llf", &p, &q, &r);
double mintime = time_ab();
printf("%.2f\n", mintime);
}
return 0;
}