题意
有n 种工作,做1 单位时间的第i 种工作可以获得ai经验和bi 金钱,现在需要p 经验和q 金钱,问至少需要工作多久。工作时间可以不是整数
题解
一个显然的结论
如果你把一个点看做一个点
那么两个点
(x1,y1)
(
x
1
,
y
1
)
和
(x2,y2)
(
x
2
,
y
2
)
那么他可以取到这两个点间的所有值
先新加入三个点
(0,0)
(
0
,
0
)
,
(xmax,0)
(
x
m
a
x
,
0
)
,
(0,ymax)
(
0
,
y
m
a
x
)
那么我们显然的可以先求出一个凸包
那么我们考虑一个点
(p,q)
(
p
,
q
)
他的最优方案
肯定是
(0,0)
(
0
,
0
)
到
(p,q)
(
p
,
q
)
这条射线和凸包的交
我们一直用这个点肯定是最优的
那么就除一下就出来了
然后我发现我以前凸包的板子有点问题,就是我没有把点去重,这样的话会导致凸包求出来不是对的。这个的话应该很容易举出反例吧。。对拍的时候发现了这个问题啊
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const double eps=1e-7;
const int N=100005;
int n;
double p,q;
struct qq
{
double x,y;
qq (){}
qq (double _x,double _y){x=_x;y=_y;}
}s[N];
int tot;
double mx=0,my=0;
double mul(qq x,qq y,qq z)
{
double x1=x.x-z.x,y1=x.y-z.y;
double x2=y.x-z.x,y2=y.y-z.y;
return x1*y2-x2*y1;
}
double dis (qq x,qq y){return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y);}
bool cmp (qq x,qq y)
{
if (abs(mul(x,y,s[1]))<eps) return dis(x,s[1])<dis(y,s[1]);
return mul(x,y,s[1])>eps;
}
int sta[N],top;
void get ()//求一个凸包
{
sta[1]=1;sta[2]=2;top=2;
for (int u=3;u<=tot;u++)
{
while (top>2&&mul(s[u],s[sta[top]],s[sta[top-1]])>eps) top--;
sta[++top]=u;
}
tot=top;
for (int u=1;u<=top;u++) s[u]=s[sta[u]];
}
bool check (int x)//0,0和这个的连线是否在他的下面
{
return s[x].y*p<=s[x].x*q;
}
qq get (qq a,qq b,qq c,qq d)//求出这两条直线的交点
{
A=mul(b,c,d),B=mul(c,a,d);
double xx,yy;
xx=b.x+(double)(a.x-b.x)*(double)A/(A+B);
yy=b.y+(double)(a.y-b.y)*(double)A/(A+B);
return qq(xx,yy);
}
int main()
{
scanf("%d%lf%lf",&n,&p,&q);
tot=1;s[tot]=qq(0,0);
for (int u=1;u<=n;u++)
{
tot++;
scanf("%lf%lf",&s[tot].x,&s[tot].y);
mx=max(mx,s[tot].x);my=max(my,s[tot].y);
}
tot++;s[tot]=qq(mx,0);
tot++;s[tot]=qq(0,my);
sort(s+2,s+1+tot,cmp);
int ToT=tot; tot=1;
for (int u=2;u<=ToT;u++)
if (s[tot].x!=s[u].x||s[tot].y!=s[u].y)
s[++tot]=s[u];
/* for (int u=1;u<=tot;u++)
printf("%lf %lf\n",s[u].x,s[u].y);*/
get();
int l=1,r=tot-1;
int lalal;//求出第一个点的连线是小于等于这个的
while (l<=r)
{
int mid=(l+r)>>1;
if (check(mid)) {lalal=mid;l=mid+1;}
else r=mid-1;
}
if (s[lalal].y*p==s[lalal].x*q)//如果是在一条直线上
{
if (s[lalal].x==0) printf("%.8lf\n",(double)q/s[lalal].y);
else printf("%.8lf\n",(double)p/s[lalal].x);
}
else
{
qq x=get(s[lalal],s[lalal+1],qq(p,q),qq(0,0));
// printf("%lf %lf\n",s[lalal].x,s[lalal].y);
// printf("%lf %lf\n",s[lalal+1].x,s[lalal+1].y);
if (x.x>eps) printf("%.8lf\n",p/x.x);
else printf("%.8lf\n",q/x.y);
}
return 0;
}