ACcoders Problem 2049 题解

题意

在一个二维平面上有两个传送带 A B AB AB C D CD CD,在传送带 A B AB AB 上的速度为 p p p,再传送带 C D CD CD 上的速度为 q q q,不在传送带上的速度为 r r r,现已给出 A , B , C , D A,B,C,D A,B,C,D 的坐标以及各自的速度,问从 A A A D D D 的最短时间为多少。

思路

我们如果要从 A A A 跑到 D D D,就绝对会有一部分的路程不在传送带上(如果他们两个重合,当我没说),那么绝对会有一点 N N N 从传送带 A B AB AB 上跑下来,还会有一点 M M M 从不在传送带的的区域跑上来,所以我们便可以设从 A A A D D D 的最短时间为
A N p + N M r + M B q \frac{AN}{p}+\frac{NM}{r}+\frac{MB}{q} pAN+rNM+qMB

两点具体距离可以用欧氏距离来求。

这时,这个式子包含两个未知数,找最小值的时候会变的非常麻烦,那该怎么办呢?

我们考虑将 N N N 设为一个参数,那么这时候要找的就是
f ( N ) = N M r + M B q f(N)=\frac{NM}{r}+\frac{MB}{q} f(N)=rNM+qMB

的最小值。我们可以用软件画一下这个函数(我不会告诉你我其实不会证),很容易发现它是一个单峰函数。

考虑三分 f ( x ) f(x) f(x) 的最小值,从而再返回得出整个问题的答案。

现在我们得出来了 f ( N ) f(N) f(N),那么这时答案即为 A N p + f ( N ) \displaystyle \frac{AN}{p}+f(N) pAN+f(N),但是我们并不知道 N N N,那该怎么办呢?

我们再用软件画一下此时的函数图像,发现又是一个单峰函数(还是不会证/kk),我们再三分当前函数的最小值,从而得出整个问题的答案(保留 2 2 2 为小数)。

代码

#include<bits/stdc++.h>
using namespace std;
double ax,ay,bx,by;
double cx,cy,dx,dy;
double p,q,r;
double dist(double x1,double y1,double x2,double y2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double f(double x1,double y1,double x2,double y2){
	return dist(x1,y1,x2,y2)/r+dist(x2,y2,dx,dy)/q;
}
double work(double x,double y)
{
	double lx=cx,ly=cy,rx=dx,ry=dy;
	while(dist(lx,ly,rx,ry)>1e-6)
	{
		double midx=(rx-lx)/3.0,midy=(ry-ly)/3.0;
		double lmidx=lx+midx,lmidy=ly+midy;
		double rmidx=rx-midx,rmidy=ry-midy;
		double tmp1=f(x,y,lmidx,lmidy),tmp2=f(x,y,rmidx,rmidy);
		if(tmp1>tmp2) lx=lmidx,ly=lmidy;
		else rx=rmidx,ry=rmidy;
	}
	return f(x,y,lx,ly);
}
double calc()
{
	double lx=ax,ly=ay,rx=bx,ry=by;
	while(dist(lx,ly,rx,ry)>1e-6)
	{
		double midx=(rx-lx)/3.0,midy=(ry-ly)/3.0;
		double lmidx=lx+midx,lmidy=ly+midy;
		double rmidx=lmidx+midx,rmidy=lmidy+midy;
		double tmp1=work(lmidx,lmidy)+dist(ax,ay,lmidx,lmidy)/p;
		double tmp2=work(rmidx,rmidy)+dist(ax,ay,rmidx,rmidy)/p;
		if(tmp1>tmp2) lx=lmidx,ly=lmidy;
		else rx=rmidx,ry=rmidy;
	}
	return work(lx,ly)+dist(ax,ay,lx,ly)/p;
}
int main()
{
	scanf("%lf %lf %lf %lf",&ax,&ay,&bx,&by);
	scanf("%lf %lf %lf %lf",&cx,&cy,&dx,&dy);
	scanf("%lf %lf %lf",&p,&q,&r);
	printf("%.2lf",calc());
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值