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

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84587054

题目链接:哆啦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
*/







猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/84587054
今日推荐