【bzoj1857】[Scoi2010]传送带 三分法

三分法
这个问题看上去像是单峰的,于是可以三分求答案
大致思路是当前区间为[l,r]
mid=(l+r)/2,midmid=(mid+r)/2
如果mid比较靠近极值点,则r=midmid
如果midmid比较靠近极值点,则l=mid


首先三分出AB上的点E,表示先从A走到点E
然后三分出CD上的点F,表示从点E走到点F,再走到点D

三分套三分


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define eps 1e-9

using namespace std;

struct yts
{
	double x,y;
}a,b,c,d;

yts cal(yts x,yts y,double p)
{
	yts ans;
	ans.x=x.x+(y.x-x.x)*p;
	ans.y=x.y+(y.y-x.y)*p;
	return ans;
}

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

double p,q,r;

double calc(yts x,yts y)
{
	return dis(a,x)/p+dis(x,y)/r+dis(y,d)/q;
}

double solve(yts t)
{
	double l=0.0,r=1.0,ans;
	while (fabs(l-r)>eps)
	{
		double mid=(l+r)/2.0,midmid=(mid+r)/2.0;
		yts x=cal(c,d,mid),y=cal(c,d,midmid);
		if (calc(t,x)<calc(t,y)) ans=mid,r=midmid; else ans=midmid,l=mid;
	}
	yts x=cal(c,d,ans);
	return calc(t,x);
}

int main()
{
	scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
	scanf("%lf%lf%lf%lf",&c.x,&c.y,&d.x,&d.y);
	scanf("%lf%lf%lf",&p,&q,&r);
	double l=0.0,r=1.0,ans;
	while (fabs(l-r)>eps)
	{
		double mid=(l+r)/2.0,midmid=(mid+r)/2.0;
		yts x=cal(a,b,mid),y=cal(a,b,midmid);
		if (solve(x)<solve(y)) ans=mid,r=midmid; else ans=midmid,l=mid;
	}
	yts x=cal(a,b,ans);
	printf("%.2lf\n",solve(x));
	return 0;
}


你可能感兴趣的:(【bzoj1857】[Scoi2010]传送带 三分法)