Pipe - POJ 1039(线段相交交点)

题目大意:有一个不反光并且不透光的管道,现在有一束光线从最左端进入,问能达到的最右端是多少,输出x坐标。
 
分析:刚开始做是直接枚举两个点然后和管道进行相交查询,不过这样做需要考虑的太多,细节不容易掌控。后来发现其实只需要对接口进行一下相交查询就简单多了,因为只需要考虑能不能通过每个截口就可以了,而且这样做的好处还有没有平行线和重叠线的情况,因为所有的截口都是垂直于x轴的,换一种想法海阔太空啊。
 
代码如下:
==========================================================================================================================
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;

const int MAXN = 107;
const double EPS = 1e-8;
const double oo = 1e9+7;

int Sign(double t)
{
    if(t > EPS)return 1;
    if(fabs(t)<EPS)return 0;
    return -1;
}

struct Point
{
    double x, y;
    Point(double x=0, double y=0):x(x), y(y){}
    Point operator - (const Point &t)const{
        return Point(x-t.x, y-t.y);
    }
    double operator ^(const Point &t)const{
        return x*t.y - y*t.x;
    }
    bool operator == (const Point &t)const{
        return fabs(x-t.x)<EPS && fabs(y-t.y)<EPS;
    }
};
struct Segment
{
    Point S, E;
    double a, b, c;///ax + by = c;

    Segment(Point S=0, Point E=0):S(S),E(E){
        ///求线段所在的直线的常数项
        a = S.y - E.y;
        b = E.x - S.x;
        c = E.x*S.y - S.x*E.y;
    }
    bool Inters(const Segment &tmp) const{
        int t1 = Sign((S-E)^(tmp.S-E));
        int t2 = Sign((S-E)^(tmp.E-E));
        ///不存在平行,或者共线情况,有一点相交都算相交
        if(t1+t2==2 || t1+t2==-2)
            return false;
        else
            return true;
    }
    Point crossNode(const Segment &tmp)const{
        ///求交点
        Point t;
        t.x = (c*tmp.b-tmp.c*b) / (a*tmp.b-tmp.a*b);
        t.y = (c*tmp.a-tmp.c*a) / (b*tmp.a-tmp.b*a);

        return t;
    }
    void MakeNewSeg(double Lx, double Rx)
    {///构造新的线段,与原来的线段共线
        S.x = Lx, S.y = (c-a*Lx) / b;
        E.x = Rx, E.y = (c-a*Rx) / b;
    }
};

double FindMinX(Segment s, Segment sg[], int N)
{
    double ans=oo;

    for(int i=1; i<N; i++)
    {
        if(s.Inters(sg[i]))
            continue;

        Segment t1(sg[i-1].S, sg[i].S);
        Segment t2(sg[i-1].E, sg[i].E);

        if(s.Inters(t1))
        {
            Point tmp = s.crossNode(t1);
            ans = tmp.x;
        }
        if(s.Inters(t2))
        {
            Point tmp = s.crossNode(t2);

            if(fabs(ans-oo) < EPS)
                ans = tmp.x;
            else
                ans = max(ans, tmp.x);
        }

        break;
    }

    return ans;
}

int main()
{
    int N;

    while(scanf("%d", &N) != EOF && N)
    {
        Point p[MAXN];
        Segment sg[MAXN];

        int k=0;

        for(int i=0; i<N; i++, k+=2)
        {
            scanf("%lf%lf", &p[k].x, &p[k].y);
            p[k+1].x = p[k].x, p[k+1].y = p[k].y - 1.0;
            sg[i] = Segment(p[k], p[k+1]);
        }

        double ans = -oo;

        for(int i=0; i<k; i++)
        for(int j=i+1; j<k; j++)
        {
            if(fabs(p[i].x-p[j].x) < EPS)
                continue;

            Segment s(p[i], p[j]);
            s.MakeNewSeg(sg[0].S.x, sg[N-1].S.x);

            if(s.Inters(sg[0]))
                ans = max(ans, FindMinX(s, sg, N));
           /// printf("i=%d, j=%d, ans=%f\n", i, j, ans);
        }

        if(fabs(ans-oo) < EPS)
            printf("Through all the pipe.\n");
        else
            printf("%.2f\n", ans);
    }

    return 0;
}

 

posted @ 2015-09-09 23:11  无忧望月  阅读(118)  评论(0编辑  收藏  举报
levels of contents