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; }