1. 程式人生 > >poj 1066 Treasure Hunt(線段相交)

poj 1066 Treasure Hunt(線段相交)

題意:

給你一個100*100的正方形,再給你n條線(牆),保證線段一定在正方形內且端點在正方形邊界(外牆),最後給你一個正方形內的點(保證不再牆上)

告訴你牆之間(包括外牆)圍成了一些小房間,在小房間內可以從房間邊界(牆)的中點走過這堵牆,問你從給定的點走到外牆外最少走過的牆數。

題解:直接把中心點與邊界點連成線段,並判斷有多少條線段與之相交,最小的相交數就是答案,詳情見程式碼。

///把中心點與邊界上的點連線,遍歷n條線段,有多少次相交,就要破多少個牆

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

using namespace std;

#define INF 0x3f3f3f3f

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

struct Line{
    point a,b;
    Line(){}
    Line(point _a,point _b){
        a=_a;b=_b;
    }
};

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)<1e-8) 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;}
bool isCross(point s1,point e1,point s2,point e2)///判斷線段相交判定
{

    ///第一步,快速排斥實驗
    if(!(min(s1.x,e1.x)<=max(s2.x,e2.x)&&min(s2.x,e2.x)<=max(s1.x,e1.x)&&
       min(s1.y,e1.y)<=max(s2.y,e2.y)&&min(s2.y,e2.y)<=max(s1.y,e1.y))) return false;

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

    ///==0表示,相交於端點也認定為相交
//    printf("c1=%f,c2=%f,c3=%f,c4=%f\n",c1,c2,c3,c4);
    if(dcmp(c1*c2)>0&&dcmp(c3*c4)>0) return true;

    return false;
}


Line line[50];
int n;

int check(point s1,point e1)
{
        int item=0;
    for(int i=1;i<=n;i++)
    {
        if(isCross(s1,e1,line[i].a,line[i].b)) item++;
        ///此題相交於端點不算
    }
    return item;
}


int main()
{

    while(~scanf("%d",&n))
    {

        double x1,y1,x2,y2;

        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i]=Line(point(x1,y1),point(x2,y2));
        }

        point center;

        scanf("%lf%lf",&center.x,&center.y);
        if(n==0){
            printf("Number of doors = 1\n");continue;
        }
        int mins=INF;

        for(int i=1;i<=n;i++) ///遍歷邊界的點
        {
            mins=min(mins,check(line[i].a,center));
            mins=min(mins,check(line[i].b,center));
        }

        mins=min(mins,check(point(0,0),center)); ///四個頂角
        mins=min(mins,check(point(0,100),center));
        mins=min(mins,check(point(100,0),center));
        mins=min(mins,check(point(100,100),center));

        printf("Number of doors = %d\n",mins+1);
    }

    return 0;

}