poj 1066 Treasure Hunt(线段相交)

题目链接:poj 1066

题意:

给你一个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;

}











 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值