题目链接
题意:
给出n个人,还有他们在铁人三项中游泳、自行车和赛跑的速度,问通过合理设计三个比赛的长度,哪些人可能成为冠军(不能是并列的)。
解法:
设行程总长度为1,其中游泳的长度为x,自行车的长度为y,则赛跑的长度为1-x-y,若i可能成为冠军,则 令f(i)=xV[i]+yU[i]+1−x−yW[i],有f(i)<f(j)(j≠i) 之后就是解不等式组了。
可以将速度同时扩大k倍。有一个重要的剪枝就是如果j的各方面速度均>=i,那么直接输出no,或者是如果j的各方面速度均<=i,那么不用考虑i-j不等式的半平面。
这样做就是为了减少精度误差导致wa,貌似后面的数据精度要求很高。
具体的做法好像有两种:一种是计算半平面交之后剩下来的点数,还有一种是计算半平面交之后剩下凸包的面积,discuss里说后一种方法精度要求极高。对于后一种方法,我还是需要加上剪枝才能ac。
第一种做法,在半平面交时,我觉得最好是剔除正好在线上的点,因为应该不会出现退化成点之类的现象。
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s) memset(a,x,(s)*sizeof a[0])
#define mem(a,x) memset(a,x,sizeof a)
#define ysk(x) (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 100 ;
const double PI=acos(-1.0);
const double eps=1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y) {};
bool operator ==(const Point B)const {return dcmp(x-B.x)==0&&dcmp(y-B.y)==0;}
bool operator<(const Point& b)const
{
return dcmp(x-b.x)<0|| dcmp(x-b.x)==0 &&dcmp(y-b.y)<0;
}
};
typedef Point Vector;
Vector operator -(Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y); }
double Cross(Vector A,Vector B)//叉乘
{
return A.x*B.y-A.y*B.x;
}
double Dot(Vector A,Vector B)//点乘
{
return 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 p) {return Vector(A.x*p,A.y*p); }
Vector operator /(Vector A,double p) {return Vector(A.x/p,A.y/p); }
Vector operator -(Vector A) {return Vector(-A.x,-A.y);}
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
struct Line
{
Point p,p2;
Vector v;
double ang;
Line(){}
Line(Point a,Vector v):p(a),v(v){ang=atan2(v.y,v.x); }//点线式
void twoPointIntial(Point p,Point p2)//两点式
{
this->p=p;
this->p2=p2;
v= p2-p;
ang=atan2(v.y,v.x);
}
Point point(double t)//参数方程求参数t对应点
{
return p+v*t;
}
bool operator<(const Line & L)const
{
return ang<L.ang;
}
};
Point GetIntersection(Line a,Line b)
{
Vector u=a.p-b.p;
double t=Cross(b.v,u)/Cross(a.v,b.v);
return a.p+a.v*t;
}
bool OnRight(Line L,Point p)
{
return dcmp(Cross(L.v,p-L.p))<=0;
}
int HalfplaneIntersection(Line* L,int n)
{
sort(L,L+n);
int first,last;
Point *p=new Point[n];
Line *q=new Line[n];
q[first=last=0]=L[0];
for(int i=1;i<n;i++)
{
while(first<last&&OnRight(L[i],p[last-1] ) ) last--;
while(first<last&&OnRight(L[i],p[first])) first++;
q[++last]=L[i];
if(fabs(Cross(q[last].v,q[last-1].v) )<eps )
{
last--;
if(!OnRight(q[last],L[i].p) ) q[last]=L[i];
}
if(first<last) p[last-1]=GetIntersection(q[last-1],q[last] );
}
while(first<last&&OnRight(q[first],p[last-1])) last--;
if(last-first<=1) return 0;//小于3个,不存在
p[last]=GetIntersection(q[last],q[first]);
return last-first+1;
}
double V[maxn+3],U[maxn+3],W[maxn+3];
Line L[maxn+6];
int main()
{
std::ios::sync_with_stdio(false);
int n;
double k=1e4;
while(cin>>n)
{
for0(i,n) cin>>V[i]>>U[i]>>W[i];
for0(i,n)
{
int nL=0;
bool ok=1;
for0(j,n) if(i!=j)
{
if(dcmp(V[j]-V[i])>=0&&dcmp(U[j]-U[i])>=0&&dcmp(W[j]-W[i])>=0 ) ok=0;
double a= (k/V[j]-k/W[j])-(k/V[i]-k/W[i]);
double b= (k/U[j]-k/W[j])-(k/U[i]-k/W[i]);
double c=k/W[j]-k/W[i];// ax+by=c>0
Vector v(b,-a);//这就够了,*********************
Point p;
if(dcmp(b)!=0) p=Point(0,-c/b);
else if(dcmp(a)!=0) p=Point(-c/a,0);
else {p=Point(0,c);v=Vector(1,0);}
L[nL++]=Line(p,v);
// printf("i=%d,j=%d\n",i,j);
// cout<<a<<" "<<b<<" "<<c<<endl;
// cout<<nL-1<<" "<<L[nL-1].p.x<<" "<<L[nL-1].p.y<<" "<<L[nL-1].v.x<<" "<<L[nL-1].v.y<<endl;
}
if(ok)
{
L[nL++]=Line(Point(0,0),Vector(0,-1));//x>0
L[nL++]=Line(Point(0,0),Vector(1, 0));//y>0
L[nL++]=Line(Point(0,1),Vector(-1,1));//x+y<1
if(!HalfplaneIntersection(L,nL) ) ok=0;
}
if(ok) puts("Yes");
else puts("No");
}
}
return 0;
}