syoj.1827. 线段传送带题解

发布时间 2023-12-19 18:05:31作者: Moyyer_suiy

前情提要-三分

1827. 线段传送带

P2571 [SCOI2010] 传送带

省流:三分套三分。


在二维平面上有两个传送带,一个从 A 点到 B 点,一个从 C 点到 D 点,速度分别是 p 和 q,在平面内其他点的速度为 r。求 A 点到 D 点的最小速度。

考虑从 A 到 D 的路程一定是 \(AE+EF+FD\),即通过这两个点连接这两个传送带,E 在第一个传送带上,F 同理在第二个。

所以答案求一个 \({(dis(A,E)/p+dis(E,F)/r+dis(F,D)/q)}_{min}\)。 这是个二元函数。

不妨将这个式子拆成两个函数,以确定参数 E,对于 \(f(E)\) 解出一个 F 使得 \((dis(E,F)/r+dis(F,D)/q)min\)。那这个单峰函数可以用三分求最值。

同理,上式外面再套一个求 E 的式子,解出一个 E 使得 \((dis(A,E)/p+f(E))min\)。这个单峰函数也可以用三分求解。

于是三分套三分。

#include<bits/stdc++.h>
#define db double
using namespace std;
const db eps=1e-6;
db ax,ay,bx,by,cx,cy,dx,dy,p,q,r;
db dis(db x,db y,db xx,db yy){
	return sqrt((yy-y)*(yy-y)+(xx-x)*(xx-x));
}
db f3(db x,db y,db xx,db yy){//E & F 
	return dis(x,y,xx,yy)/r+dis(xx,yy,dx,dy)/q;
}
db f2(db ex,db ey){//F
	db lx=cx,ly=cy,rx=dx,ry=dy;//CD
	while(dis(lx,ly,rx,ry)>eps){
		db x=(rx-lx)/3.0,y=(ry-ly)/3.0;
		db lmidx=lx+x,lmidy=ly+y,rmidx=rx-x,rmidy=ry-y;
		db ans1=f3(ex,ey,lmidx,lmidy);
		db ans2=f3(ex,ey,rmidx,rmidy);
		if(ans2-ans1>eps) rx=rmidx,ry=rmidy;
		else lx=lmidx,ly=lmidy;
	}
	return f3(ex,ey,lx,ly);
}
db f1(){//E
	db lx=ax,ly=ay,rx=bx,ry=by;
	while(dis(lx,ly,rx,ry)>eps){//AB
		db x=(rx-lx)/3.0,y=(ry-ly)/3.0;
		db lmidx=lx+x,lmidy=ly+y,rmidx=rx-x,rmidy=ry-y;
		db ans1=f2(lmidx,lmidy)+dis(ax,ay,lmidx,lmidy)/p;
		db ans2=f2(rmidx,rmidy)+dis(ax,ay,rmidx,rmidy)/p;
		if(ans2-ans1>eps) rx=rmidx,ry=rmidy;
		else lx=lmidx,ly=lmidy;
	}
	return f2(lx,ly)+dis(ax,ay,lx,ly)/p;
}
int main(){
	scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",&ax,&ay,&bx,&by,&cx,&cy,&dx,&dy,&p,&q,&r);
	printf("%.2lf",f1());
	return 0;
}