poj 1755 Triathlon (半平面交解一元二次不等式)(切割求半平面交)
阿新 • • 發佈:2018-12-15
題目連結:哆啦A夢傳送門
參考連結:https://blog.csdn.net/acm_cxlove/article/details/7883370
題目:鐵人三項,每個人在某一項中有確定的速度,裁判可以決定某一項比賽的路程為多少,問對於某個人,是否存在一種安排能使他拿到第一,而且不能是並列。
題解:我們假設三項的路程分別人X,Y,Z。
A的時間為X / U1+Y / V1+Z / W1 B的時間為X / U2 +Y / V2 +Z / W2
如果A想要獲勝媽, X / U2 +Y / V2 +Z / W2 - (X / U1+Y / V1+Z / W1)>0
故,同理,b,c也一樣求,因為我們不需要求出變數X,Y,Z的值,而且Z>0,所以把不等式兩邊同時除以Z,則把X/Z看成一個未知量,Y/Z看成另外一個。
注意下:A==0&&B==0&&C<=0說明不等式無解,直接返回。
還有精度問題:我是弄到1e-18才A的,1e-8,不行。
切割半平面時,還有一個細節,不是很懂,就是為什麼要>-esp,而不是>=esp,以後再處理。
還注意一點的是:順時針是大於0,逆時針是小於0,例如:(0,0),(1,2) 順時針是 2*x-y=0,逆時針是 -2*x+y=0。
///點是順時針儲存的 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn=1510; #define INF 1<<28; struct point{ double x,y; point(){} point(double _x,double _y){ x=_x;y=_y; } }; struct node{ double u,v,w; }; struct LINE{ point s,t; LINE(){} LINE(point _s,point _t){ s=_s;t=_t; } }; point operator + (point a,point b) { return point(a.x+b.x,a.y+b.y);} point operator - (point a,point b) { return point(a.x-b.x,a.y-b.y);} point operator * (point a,double p) { return point(a.x*p,a.y*p);} point operator / (point a,double p) { return point(a.x/p,a.y/p);} const double esp=1e-18; int dcmp(double x){ if(fabs(x)<esp) return 0; else return x<0?-1:1; } bool operator < (const point &a,const point &b){ return dcmp(a.x-b.x)<0||(dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)<0); } bool operator == (const point &a,const point &b){ return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } node poly[maxn]; ///記錄最開始的多邊形 point q[maxn]; ///臨時儲存新切割的多邊形 point p[maxn]; ///儲存新切割出的多邊形 int n,m; double a,b,c; void getline(point P,point Q)///獲取直線ax+by+c==0 { a=Q.y-P.y; b=P.x-Q.x; c=P.y*Q.x-P.x*Q.y; } double Cross(point a,point b) { return a.x*b.y-a.y*b.x;} point Getlinenode(point p1,point p2) ///獲取直線ax+by+c==0 和點p1和p2所連直線的交點 { double u=fabs(a*p1.x+b*p1.y+c); double v=fabs(a*p2.x+b*p2.y+c); point ans; ans.x=(p1.x*v+p2.x*u)/(u+v); ans.y=(p1.y*v+p2.y*u)/(u+v); return ans; } void cut(point p[],int &cnt ) ///用直線ax+by+c==0切割多邊形 { int tmp=0; for(int i=1;i<=cnt;i++) { ///題目是順時鐘給出點的,所以一個點在直線右邊的話,那麼帶入值就會大於等於0 if(a*p[i].x+b*p[i].y+c>-esp) ///這裡>-esp,還不是很懂,為什麼不是>=esp q[++tmp]=p[i]; ///說明這個點還在切割後的多邊形內,將其保留 else{ ///該點不在多邊形內,但是它和它相鄰的點構成直線與ax+by+c==0所構成的交點可能在新切割出的多邊形內, if(a*p[i-1].x+b*p[i-1].y+c>esp)///所以保留交點 q[++tmp]=Getlinenode(p[i-1],p[i]); if(a*p[i+1].x+b*p[i+1].y+c>esp) q[++tmp]=Getlinenode(p[i+1],p[i]); } } for(int i=1;i<=tmp;i++) p[i]=q[i]; p[0]=q[tmp]; p[tmp+1]=q[1]; cnt=tmp; } int solve(int id) { p[1].x=0;p[1].y=0; ///初始化平面 p[2].x=0;p[2].y=INF; p[3].x=INF;p[2].y=INF; p[4].x=INF;p[4].y=0; p[0]=p[4]; p[5]=p[1]; int cnt=4; for(int i=0;i<n;i++) { if(i==id) continue; a=(poly[id].u-poly[i].u)/(poly[id].u*poly[i].u); b=(poly[id].v-poly[i].v)/(poly[id].v*poly[i].v); c=(poly[id].w-poly[i].w)/(poly[id].w*poly[i].w); ///如果a=0,b=0,c<0,無解,返回0 if(dcmp(a)==0&&dcmp(b)==0&&c<esp) return 0; ///判斷小於0,要<esp,dcmp(c)<0,不能A,還未知 // if(a==0&&b==0&&c<esp) return 0; cut(p,cnt); ///用直線ax+by+c==0切割多邊形 } double area=0; for(int i=2;i<cnt;i++) ///計算面積 area+=Cross(p[i]-p[1],p[i+1]-p[1]); area=area/2.0; if(dcmp(area)==0) return 0; ///面積為0,說明無解,返回0 else return 1; } int main() { while(~scanf("%d",&n)) { for(int i=0;i<n;i++) scanf("%lf%lf%lf",&poly[i].u,&poly[i].v,&poly[i].w); for(int i=0;i<n;i++) { if(solve(i)) puts("Yes"); else puts("No"); } } return 0; } /* p[1].x=0.357143,p[1].y=0.035714 p[2].x=1.624650,p[2].y=1.176471 p[3].x=4.666667,p[3].y=0.466667 */