1. 程式人生 > >poj 1755 Triathlon (半平面交解一元二次不等式)(切割求半平面交)

poj 1755 Triathlon (半平面交解一元二次不等式)(切割求半平面交)

 

題目連結:哆啦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

a={\color{Red} \frac{1}{U2}-\frac{1}{U1}}=\frac{U1-U2}{U1*U2},同理,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
*/