题目描述
题目大意:n个人参加比赛,先跑步和自行车的总路程为s,其中跑步为k,走路为r,每个人跑步和自行车都有一个速度。求出对第n个人最有利的k和r,使其获得冠军,并且领先第二名的时间最多。
题解
首先将每个人的k-时间方程写出来 y=x/v1+(s-x)/v2=(1/v1-1/v2)x+s/v2
这样得到了n个方程,用半平面交求凸壳(其它比半平面交高明到不知道哪里去了的办法都资瓷
求出凸壳之后判断第n条直线是否在凸壳上有位置(有一个点也包括),如果有的话,就得到了一个合法的区间,直观观察可以发现和第二名的差距在区间上是单峰的,可以三分求解
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 105
const double eps=1e-9;
const double inf=1e9;
int dcmp(double x)
{
if (x<=eps&&x>=-eps) return 0;
return (x>0)?1:-1;
}
struct Vector
{
double x,y;
Vector(double X=0,double Y=0)
{
x=X,y=Y;
}
};
typedef Vector Point;
struct Line
{
double k,b;
Point p,q;
Line(double K=0,double B=0)
{
k=K,b=B;
}
};
Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator * (Vector a,double b){return Vector(a.x*b,a.y*b);}
int n,cnt;
double s;
Line line[N];
Point poly[N],npoly[N];
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
bool ins(Point A,Point B,Point C,Point D)
{
Vector v,u,w;
v=B-A,u=C-A,w=D-A;
if (dcmp(Cross(v,u))==dcmp(Cross(v,w))) return 0;
v=D-C,u=A-C,w=B-C;
if (dcmp(Cross(v,u))==dcmp(Cross(v,w))) return 0;
return 1;
}
Point GLI(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
void init()
{
cnt=0;
poly[++cnt]=Point(0,0);
poly[++cnt]=Point(0,inf);
poly[++cnt]=Point(s,inf);
poly[++cnt]=Point(s,0);
}
void halfp(Point A,Point B)
{
Point C,D;int ncnt=0;
for (int i=1;i<=cnt;++i)
{
C=poly[i];
D=poly[i%cnt+1];
if (dcmp(Cross(C-A,B-A))>=0)
npoly[++ncnt]=C;
if (ins(A,B,C,D))
npoly[++ncnt]=GLI(A,B-A,C,D-C);
}
cnt=ncnt;
for (int i=1;i<=cnt;++i) poly[i]=npoly[i];
}
double check(double x)
{
double Min=inf;
for (int i=1;i<n;++i)
Min=min(Min,line[i].k*x+line[i].b);
return Min-(line[n].k*x+line[n].b);
}
double find(double l,double r)
{
double mid1,mid2,ans1,ans2,ans;
while (r-l>eps)
{
mid1=l+(r-l)/3.0;
mid2=r-(r-l)/3.0;
ans1=check(mid1);
ans2=check(mid2);
if (ans1>=ans2) ans=mid1,r=mid2;
else ans=mid2,l=mid1;
}
return ans;
}
int main()
{
scanf("%lf%d",&s,&n);
for (int i=1;i<=n;++i)
{
double v1,v2;scanf("%lf%lf",&v1,&v2);
line[i]=Line(1/v1-1/v2,s/v2);
line[i].p.x=0,line[i].p.y=line[i].b;
line[i].q.x=s,line[i].q.y=line[i].k*s+line[i].b;
}
init();
for (int i=1;i<=n;++i)
halfp(line[i].p,line[i].q);
bool flag=0;double ans;
for (int i=1;i<=cnt;++i)
{
double xa=poly[i].x,ya=poly[i].y,xb=poly[i%cnt+1].x,yb=poly[i%cnt+1].y;
if (!dcmp(xa-xb)||(!dcmp(ya)&&!dcmp(yb))) continue;
double know=(ya-yb)/(xa-xb);
double bnow=ya-xa*know;
if (!dcmp(line[n].k-know)&&!dcmp(line[n].b-bnow))
{
flag=1;
ans=find(poly[i].x,poly[i%cnt+1].x);
break;
}
}
if (!flag)
{
for (int i=1;i<=cnt;++i)
if (!dcmp(line[n].k*poly[i].x+line[n].b-poly[i].y))
{
flag=1;
ans=poly[i].x;
break;
}
if (!flag) puts("NO");
else printf("%.2lf %.2lf %.0lf\n",ans,s-ans,check(ans)*3600+eps);
}
else printf("%.2lf %.2lf %.0lf\n",ans,s-ans,check(ans)*3600+eps);
}