POJ 1755 Triathlon

http://poj.org/problem?id=1755

题意:铁人三项,每个人有自己在每一段的速度,求有没有一种3条路线长度都不为0的设计使得某个人能严格获胜?

我们枚举每个人获胜,得到不等式组:s1/v1+s2/v2+s3/v3<s1/v1'+s2/v2'+s3/v3' 是三维半平面交?接着看

我们令两边同时除以s3得到

(s1/s3)*(1/v1)+(s2/s3)*(1/v2)+(1/v3)<(s1/s3)*(1/v1')+(s2/s3)*(1/v2')+(1/v3')

这样s1/s3和s2/s3就变成了唯二的变量了,这样不等式组就变成了二元一次不等式组了,用半平面交就可以解决了。

注意有些地方:

eps要设置到1e-16

如果一个人有2个速度和另一个人相等,直接特判掉第三个,不建直线。

#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
const double eps=1e-16;
const double inf=99999999;
struct Point{
 double x,y;
 Point(){}
 Point(double x0,double y0):x(x0),y(y0){}
}p[200005];
struct Line{
 Point s,e;
 double slop;
 Line(){}
 Line(Point s0,Point e0):s(s0),e(e0){}
}l[200005],c[200005];
int tot,n,v1[200005],v2[200005],v3[200005],num[200005];
int sgn(double x){
 if (x>eps) return 1;
 if (x<-eps) return -1;
 return 0;
}
int read(){
 int t=0,f=1;char ch=getchar();
 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
 return t*f;
}
double operator *(Point p1,Point p2){
 return p1.x*p2.y-p1.y*p2.x;
}
Point operator -(Point p1,Point p2){
 return Point(p1.x-p2.x,p1.y-p2.y);
}
bool pd(int id){
 for (int i=1;i<=n;i++)
  if (i!=id)
 {
  int cnt=0,ans1=0,ans2=0;
  if (v1[i]==v1[id]) cnt++;
  else ans1=v1[id],ans2=v1[i];
  if (v2[i]==v2[id]) cnt++;
  else ans1=v2[id],ans2=v2[i];
  if (v3[i]==v3[id]) cnt++;
  else ans1=v3[id],ans2=v3[i];
  if (cnt==3) return 0;
  else if (cnt==2){
   if (ans1<=ans2) return 0;
  }
  num[i]=cnt;
 }
 return 1;
}
void build(int id){
    tot=0;
    l[++tot].s=Point(0,inf);l[tot].e=Point(0,0);
    l[++tot].s=Point(0,0);l[tot].e=Point(inf,0);
    l[++tot].s=Point(inf,0);l[tot].e=Point(0,inf);
    for (int i=1;i<=n;i++)
     if (i!=id){
     if (num[i]==2) continue;
     tot++;
     double A=((double)v1[i]-v1[id])/((double)v1[id]*v1[i]); 
     double B=((double)v2[i]-v2[id])/((double)v2[id]*v2[i]);
     double C=((double)v3[i]-v3[id])/((double)v3[id]*v3[i]);
     int a=sgn(A),b=sgn(B),c=sgn(C);
     if (a==0){
      l[tot].s.x=-1;l[tot].s.y=(-C)/B;
      l[tot].e.x=1;l[tot].e.y=(-C)/B;
      if (b>0) std::swap(l[tot].s,l[tot].e);
     }else if (b==0){
      l[tot].s=Point((-C)/A,-1);
      l[tot].e=Point((-C)/A,1);
      if (a<0) std::swap(l[tot].s,l[tot].e);
     }else{
      l[tot].s=Point(-1,-((-1)*A+C)/B);
      l[tot].e=Point(1,-(A+C)/B);
      if (b>0) std::swap(l[tot].s,l[tot].e);
     }
 }
 for (int i=1;i<=tot;i++)
  l[i].slop=atan2(l[i].e.y-l[i].s.y,l[i].e.x-l[i].s.x);
}
Point inter(Line p1,Line p2){
 double k1=(p2.e-p1.s)*(p1.e-p1.s);
 double k2=(p1.e-p1.s)*(p2.s-p1.s);
 double t=(k2)/(k1+k2);
 double x=p2.s.x+(p2.e.x-p2.s.x)*t;
 double y=p2.s.y+(p2.e.y-p2.s.y)*t;
 return Point(x,y);
}
bool jud(Line p1,Line p2,Line p3){
 Point p=inter(p1,p2);
 return (p-p3.s)*(p3.e-p3.s)>=eps;
}
bool cmp(Line p1,Line p2){
 if (fabs(p1.slop-p2.slop)<=eps) return (p1.e-p1.s)*(p2.e-p1.s)<=0; 
 else return p1.slop<p2.slop;
}
bool phi(){
   int cnt=1;
   std::sort(l+1,l+1+tot,cmp);
   for (int i=2;i<=tot;i++)
    if (fabs(l[i].slop-l[i-1].slop)>eps) l[++cnt]=l[i];
   int L=1,R=2;c[1]=l[1];c[2]=l[2];
   for (int i=3;i<=cnt;i++){
    while (L<R&&jud(c[R],c[R-1],l[i])) R--;
    while (L<R&&jud(c[L],c[L+1],l[i])) L++;
    c[++R]=l[i];
   } 
   while (L<R&&jud(c[R],c[R-1],c[L])) R--;
   while (L<R&&jud(c[L],c[L+1],c[R])) L++;
   if (R-L+1<3) return 0;
   c[R+1]=c[L];
   cnt=0;
   for (int i=L;i<=R;i++)
    p[++cnt]=inter(c[i],c[i+1]);
   p[cnt+1]=p[1];
   double res=0;
   for (int i=1;i<=cnt;i++)
    res+=p[i]*p[i+1];
   res/=2.0;
   res=fabs(res);
   if (res<=eps) return 0;
   else return 1;  
}
bool work(int id){
   build(id);
   if (phi()) return 1;
   else return 0;
}
int main(){
   n=read();
   for (int i=1;i<=n;i++){
    v1[i]=read(),v2[i]=read(),v3[i]=read();
   }
   for (int i=1;i<=n;i++){
    if (pd(i)&&work(i)) puts("Yes");
    else puts("No");
   }
   return 0;
}

 

posted @ 2016-07-11 15:27  GFY  阅读(304)  评论(0编辑  收藏  举报