Chris and Road CodeForces - 703C 【几何 贪心 二分】

题目链接

CF703C

题意

给你一个凸多边形的车,一条街宽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;
}
posted @ 2020-05-06 17:21  xxxuanei  阅读(104)  评论(0编辑  收藏  举报