Chris and Road CodeForces - 703C 【几何 贪心 二分】
题目链接
题意
给你一个凸多边形的车,一条街宽w(y=0,y=w之间),你站在(0,0)可以以u速度往上走,车可以以v的速度往x轴负方向走,问你最少要多久你才能跨过这条街。在这个多边形的边上和顶点上不算被撞。
思路
- 两个都在移动,那就换一种坐标系,看作是人在两个方向都可以移动,可以以v的速率向x轴正方向移动,也可以以u的速率向y轴正方向移动。
- 合成速度 V ,如果可以一直移动不被车撞的话,那么这条斜率为(u/v)的直线不会穿过多边形内部。
- 所以现在的目标是,找到x轴上那个开始可以随意以合成速度 V行走的点x。总的时间就是 \(\frac{x}{v}+\frac{w}{u}\)
- 如何判断有没有穿过多边形内部?
- 第一种情况,凸多边形所有的点都在这条线的右下方:这样的话从(0,0)开始走最快,不需要找点了,时间为\(w/u\)。
- 第二种情况,凸多边形所有的点都在这条线的左上方:通过二分找点在哪。
- 如何判断所有的点是不是都在一边:高中数学线性规划里就有用到,\(y_0-k*x_0+k*x\)是不是都是正或者负。
- 注意事项:
- 由于是double,所以判断大小要用eps。
- eps太小了的话会tle 😢
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=10005;
const double eps=1e-6;
int n;
double w,v,u;
typedef pair<double,double> pa;
pa a[MAXN];
double k;
bool judge(double x){
int tot1=0,tot2=0;
for(int i=1;i<=n;i++){
if(a[i].first-k*a[i].second+k*x<eps) tot1++;
else tot2++;
if(tot1&&tot2) return false;
}
return true;
}
int main(){
scanf("%d%lf%lf%lf",&n,&w,&v,&u);
double mx=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf",&a[i].second,&a[i].first);
mx = mx<a[i].second?a[i].second:mx;
}
k=u/v;
double l=0,r=mx;
if(judge(0.0)){
printf("%.10lf\n",w/u);
return 0;
}
double mid,ans;
while(r-l>eps){
mid=(r+l)/2;
if(judge(mid)){
r=mid;
}
else l=mid;
}
printf("%.10lf\n",mid/v+w/u);
return 0;
}