1. 程式人生 > >poj 1039 Pipe (直線與線段相交判斷+列舉端點)

poj 1039 Pipe (直線與線段相交判斷+列舉端點)

題目連結:傳送門

題意:有一條寬度為1(指的是上下管壁縱座標之差,不是管道真實的寬度)的折線形管道,管道壁不透光不反光,求從管道一頭射入一束光線,光線在管道內沿直線傳播最遠能傳播多遠(橫座標能到達的最大值)。

輸入:每個測試用例一個數據塊,第一個整數為折點數(2到20之間),接下來每行一個折點座標(即上圖中的一個點[x,y],x互不相等,按增序排列),表示管道的上邊界折點,對應的下邊界折點為[x,y-1].折點數位0時表示輸入結束。

輸出:每次用例輸出一行,若光線能穿透整個管道,輸出Through all the pipe.否則輸出能到達的x值,保留兩位小數。

 

題解:直接列舉

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>

using namespace std;

struct point
{
    double x,y;
    point(){}
    point(double _x,double _y){
        x=_x;y=_y;
    }
};


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);}

bool operator < (const point &a,const point &b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
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.y-b.y)==0;
}

double Cross(point A,point B) { return A.x*B.y-A.y*B.x;}

point Getlinenode(point P,point v,point Q,point w){ ///兩引數方程求交點,(點,向量,點,向量)
    point u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}

bool isCross(point s1,point e1,point s2,point e2)///判斷直線與線段是否相交
{

    ///首先判斷向量s2e2 跨立 向量s1e1
    double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1);



    ///==0表示,相交於端點也認定為相交
    if(dcmp(c1*c2)>=0) return true;


    return false;
}

point p1[30],p2[30];
int main()
{

    int n;

    while(scanf("%d",&n)&&n)
    {
        double a,b;
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&a,&b);
            p1[i]=point(a,b);
            p2[i]=point(a,b-1);
        }

        bool flag=true;

        double ans=p1[0].x;
        for(int i=0;i<n&&flag;i++)
        {
            for(int j=0;j<n&&flag;j++)
            {
                if(i==j) continue;

                int k;
                for( k=0;k<n;k++){
                    if(!isCross(p1[i],p2[j],p1[k],p2[k])){ ///判斷直線ij與線段k是否相交
//                            
                        break;
                    }
                }

                if(k==n) {
                    flag=false;break;
                }
                else if(k>max(i,j)){
                    point item=Getlinenode(p1[i],p1[i]-p2[j],p1[k],p1[k]-p1[k-1]); 
                    if(item.x>ans) ans=item.x;
                    item=Getlinenode(p1[i],p1[i]-p2[j],p2[k],p2[k]-p2[k-1]);
                   if(item.x>ans) ans=item.x;
//                    printf("ans=%.2f,k=%d\n",ans,k);
                }
            }
        }

        if(flag){
            printf("%.2f\n",ans);
        }
        else printf("Through all the pipe.\n");
    }
    return 0;
}