题意:n个人参加一个接力赛,跑道长度为L,每个人根据跑步时的心情的不同速度也不一样,bad mood时速度为s,good mood时速度为t,每个人至少跑d米,当满足所有人都在badmood下且花费的时间不超过w的情况下,如果所有人都以goodmood跑,至少要花费多少时间。
分析:参考的HDU 4128 Running relay (贪心+凸包优化)这篇博客
参考代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define eps 1e-6
const int maxn = 1e4+10;
int n;
double d,len,w;
int sgn( double x)
{
if( x > eps)//x>0
return 1;
else if( x < -eps)//x==0
return -1;
else//x<0
return 0;
}
//x:s,y:t
//用点的横纵坐标来记录runner的速度值
struct Point{
double x,y;
Point(){}
Point( double xx, double yy)
{
x = xx;
y = yy;
}
Point operator - ( const Point &p)const
{
return Point(x-p.x,y-p.y);
}
double operator ^ ( const Point &p)const
{
return x*p.y-p.x*y;
}
bool operator < ( const Point &p)const
{
return sgn(x-p.x) < 0 || (sgn(x-p.x) == 0 && sgn(y-p.y) < 0);
}
}p[maxn],tmp[maxn];
double xmult( Point p1, Point p2, Point p3)
{
return (p2-p1)^(p3-p1);
}
//找凸包,返回节点数
int SetConvex( Point p[], int n)
{
int top = 0;
if( n == 0)
return 0;
tmp[top++] = p[0];
if( n == 1)
return 1;
tmp[top++] = p[1];
for( int i = 2; i < n; i++)
{
while( top >= 2 && sgn(xmult(tmp[top-2],tmp[top-1],p[i])) <= 0)
top--;
tmp[top++] = p[i];
}
return top;
}
//三分
double ternary( Point a, int l, int r)
{
double k = 1e30;
while( l <= r)
{
int lm = (2*l+r)/3;//l+(r-l)*1/3
int rm = (l+2*r)/3;//l+(r-l)*2/3
double ll = (a.y-tmp[lm].y)/(a.x-tmp[lm].x);
double rr = (a.y-tmp[rm].y)/(a.x-tmp[rm].x);
if( sgn(ll-rr) >= 0)
{
k = min(k,rr);
l = lm+1;
}
else
{
k = min(k,ll);
r = rm-1;
}
}
return a.y*len+(w-a.x*len)*k;
}
double work()
{
if( sgn(len) < 0 || sgn(w) < 0)//不满足条件
return -1;
sort(p,p+n);
if( sgn(w-p[0].x*len) < 0)//badmood下跑的最快的runner都跑不及
return -1;
int j = 1;
for( int i = 0; i < n; i++)
{
if( sgn(p[i].y-p[j-1].y) >= 0)//goodmood下后面的速度小,不保存
continue;
p[j++] = p[i];//速度大,保存下来
}
n = j;
if( n == 1)
return p[0].y*len;
for( j = 0; j < n && sgn(w-p[j].x*len) >= 0; j++)//找出临界点
;
int tot = j;//记录单个满足条件的数量
int sz = SetConvex(p+j,n-j);
double ans = 1e30;
for( int i = 0; i < tot; i++)
{
ans = min(ans,p[i].y*len);
ans = min(ans,ternary(p[i],0,sz-1));
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while( T--)
{
scanf("%d%lf%lf%lf",&n,&d,&len,&w);
double s,t;
double base = 0;//基础时间(也就是每个人都要跑的)
for( int i = 0; i < n; i++)
{
scanf("%lf%lf",&s,&t);
p[i].x = s;
p[i].y = t;
len -= d;
w -= p[i].x*d;
base += p[i].y*d;
}
double add = work();
if( sgn(add) < 0)
puts("No solution");
else
printf("%.2f\n",base+add);
}
return 0;
}