poj 1755 Triathlon(半平面交应用)

Triathlon
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 3451 Accepted: 876

Description

Triathlon is an athletic contest consisting of three consecutive sections that should be completed as fast as possible as a whole. The first section is swimming, the second section is riding bicycle and the third one is running. 

The speed of each contestant in all three sections is known. The judge can choose the length of each section arbitrarily provided that no section has zero length. As a result sometimes she could choose their lengths in such a way that some particular contestant would win the competition. 

Input

The first line of the input file contains integer number N (1 <= N <= 100), denoting the number of contestants. Then N lines follow, each line contains three integers Vi, Ui and Wi (1 <= Vi, Ui, Wi <= 10000), separated by spaces, denoting the speed of ith contestant in each section.

Output

For every contestant write to the output file one line, that contains word "Yes" if the judge could choose the lengths of the sections in such a way that this particular contestant would win (i.e. she is the only one who would come first), or word "No" if this is impossible.

Sample Input

9
10 2 6
10 7 3
5 6 7
3 2 7
6 2 6
3 5 7
8 4 6
10 4 2
1 8 7

Sample Output

Yes
Yes
Yes
No
No
No
Yes
No
Yes

Source

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

题意:有n个人参加三项比赛,你作为一个裁判可以随意调整三个赛段的距离(都大于0),问是否能调整使得指定的选手获胜

分析:这题主要是提前不小心看到别人的题解了= =

首先获胜者只有一个,假设赛段分别为a,b,c,则有a / vi + b / ui + c / wi < a / vj + b / uj + c / wj (0<j<n,  j!=i ) ,由于距离都大于一,我们可以这样转换,

a/c * (1/vi-1/vj) + b/c * (1/ui +1/uj) + (1/wi-1/wj)<0这样的不等式,然后用半平面表示这些不等式,求半平面交的面积是否大于0即可

注意:

1.所有距离必须大于0,所以要假设一个第一象限的限制,自己加个巨大的正方形进去就行

2.构造直线ax+by+c=0时注意 a 和 b同时为0的情况,直线转半平面的情况要讨论清楚

3.这题大家都说精度要到 1e-16,尽管我的代码也是这样,我下载数据后调试才AC的,调试的时候发现就两组数据会出错

一组要求不能直接写面积>0,一组要求面积大于eps的那个数不能太大

而1e-16刚好是介于两者之间了,比赛的话,肯定是过不了了,看来我的算法精度不够的样子啊


代码:

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int mm=111;
const double eps=1e-16;
typedef double diy;
struct point
{
    diy x,y;
    point(){}
    point(diy _x,diy _y):x(_x),y(_y){}
}g[mm];
point Vector(point s,point t)
{
    return point(t.x-s.x,t.y-s.y);
}
diy CrossProduct(point P,point Q)
{
    return P.x*Q.y-P.y*Q.x;
}
diy MultiCross(point P,point Q,point R)
{
    return CrossProduct(Vector(Q,P),Vector(Q,R));
}
struct halfPlane
{
    point s,t;
    diy angle;
    halfPlane(){}
    halfPlane(point _s,point _t){s=_s,t=_t,angle=atan2(t.y-s.y,t.x-s.x);}
}hp[mm],q[mm];
point Intersection(halfPlane P,halfPlane Q)
{
    diy a1=CrossProduct(Vector(P.s,Q.t),Vector(P.s,Q.s));
    diy a2=CrossProduct(Vector(P.t,Q.s),Vector(P.t,Q.t));
    return point((P.s.x*a2+P.t.x*a1)/(a1+a2),(P.s.y*a2+P.t.y*a1)/(a1+a2));
}
bool IsParallel(halfPlane P,halfPlane Q)
{
    return fabs(CrossProduct(Vector(P.s,P.t),Vector(Q.s,Q.t)))<eps;
}
bool cmp(halfPlane P,halfPlane Q)
{
    if(fabs(P.angle-Q.angle)<eps)
        return MultiCross(P.s,P.t,Q.s)>0;
    return P.angle<Q.angle;
}
void HalfPlaneIntersect(int n,int &m)
{
    sort(hp,hp+n,cmp);
    int i,l=0,r=1;
    for(m=i=1;i<n;++i)
        if(hp[i].angle-hp[i-1].angle>eps)hp[m++]=hp[i];
    n=m;
    m=0;
    q[0]=hp[0],q[1]=hp[1];
    for(i=2;i<n;++i)
    {
        if(IsParallel(q[r],q[r-1])||IsParallel(q[l],q[l+1]))return;
        while(l<r&&MultiCross(hp[i].s,hp[i].t,Intersection(q[r],q[r-1]))>0)--r;
        while(l<r&&MultiCross(hp[i].s,hp[i].t,Intersection(q[l],q[l+1]))>0)++l;
        q[++r]=hp[i];
    }
    while(l<r&&MultiCross(q[l].s,q[l].t,Intersection(q[r],q[r-1]))>0)--r;
    while(l<r&&MultiCross(q[r].s,q[r].t,Intersection(q[l],q[l+1]))>0)++l;
    q[++r]=q[l];
    for(i=l;i<r;++i)
        g[m++]=Intersection(q[i],q[i+1]);
}
double v[mm],u[mm],w[mm];
int i,n;
bool ok(int o)
{
    double a,b,c,area;
    int i,m=0,t;
    for(i=0;i<n;++i)
        if(i!=o)
        {
            a=(v[i]-v[o])/(v[o]*v[i]);
            b=(u[i]-u[o])/(u[o]*u[i]);
            c=(w[i]-w[o])/(w[o]*w[i]);
            if(fabs(a)<eps&&fabs(b)<eps)
            {
                if(w[i]>=w[o])return 0;
                continue;
            }
            if(fabs(a)<eps)
                hp[m++]=halfPlane(point(b<0?-1:1,-c/b),point(b<0?1:-1,-c/b));
            else if(fabs(b)<eps)
                hp[m++]=halfPlane(point(-c/a,a<0?1:-1),point(-c/a,a<0?-1:1));
            else if(b<0)
                hp[m++]=halfPlane(point(0,-c/b),point(1,-(a+c)/b));
            else hp[m++]=halfPlane(point(1,-(a+c)/b),point(0,-c/b));
        }
    hp[m++]=halfPlane(point(0,0),point(1e8,0));
    hp[m++]=halfPlane(point(1e6,0),point(1e6,1e6));
    hp[m++]=halfPlane(point(1e6,1e6),point(0,1e6));
    hp[m++]=halfPlane(point(0,1e6),point(0,0));
    HalfPlaneIntersect(m,t);
    area=0;
    g[t]=g[0];
    for(i=0;i<t;++i)
        area+=CrossProduct(g[i],g[i+1]);
    return fabs(area)>eps;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;++i)
            scanf("%lf%lf%lf",&v[i],&u[i],&w[i]);
        for(i=0;i<n;++i)
            puts(ok(i)?"Yes":"No");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值