POJ 1066 Treasure Hunt(浮点判断线段交点)

http://poj.org/problem?id=1066

在下图中,

POJ 1066 Treasure Hunt(浮点判断线段交点)_第1张图片

求解从四边到中间终点至少要穿过几堵墙。

浮点数据的线段判断是否相交。另外,我们需要设置四边的起点,不是直接遍历每个坐标,而是找已有的交点。(有一种贪心的意思)。

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-6;
struct point {
    double x,y;
};
struct edge{
    point u,v;
}eg[40];
double min(double q1,double q2){
    return q1-q2<eps?q1:q2;
}
double max(double q1,double q2){
    return q1-q2>eps?q1:q2;
}
bool on(point a,point b,point c){
    if(c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x)&&c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y))
        return 1;
    return 0;
}

double multi(point p0,point p1,point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool cross(point p1,point p2,point p3,point p4){
    bool tag=0;
    double r1=multi(p3,p4,p1),r2=multi(p3,p4,p2);
    double r3=multi(p1,p2,p3),r4=multi(p1,p2,p4);
    if(r1*r2<eps&&r3*r4<eps) tag=1;
    else if(fabs(r1)<eps&&on(p3,p4,p1))tag=1;
    else if(fabs(r2)<eps&&on(p3,p4,p2))tag=1;
    else if(fabs(r3)<eps&&on(p1,p2,p3))tag=1;
    else if(fabs(r4)<eps&&on(p1,p2,p4)) tag=1;
    return tag;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n;
    while(cin>>n){  
        point u,v;
        for(int i=0;i<n;i++)  {
            scanf("%lf%lf%lf%lf",&eg[i].u.x,&eg[i].u.y,&eg[i].v.x,&eg[i].v.y);
        }

        scanf("%lf%lf",&eg[n].u.x,&eg[n].u.y);
        if(n==0){
            puts("Number of doors = 1");
            continue;
        }
        int ans=n;
        for(int i=0;i<n;i++){  //就选择交点作为另一个端点
            eg[n].v.x=eg[i].u.x;
            eg[n].v.y=eg[i].u.y;
            int sum=0;
            for(int j=0;j<n;j++){
                if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v))  sum++;
            }
            ans=ans<sum?ans:sum;
            eg[n].v.x=eg[i].v.x;
            eg[n].v.y=eg[i].v.y;
            sum=0;
            for(int j=0;j<n;j++){
                if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v))  sum++;
            }
            ans=ans<sum?ans:sum;
        }
        printf("Number of doors = %d\n",ans);
    }
    return 0;
}

事实上,他还能代码优化:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const double eps=1e-6;
struct point {
    double x,y;
};
struct edge{
    point u,v;
}eg[40];
double multi(point p0,point p1,point p2){
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool cross(point p1,point p2,point p3,point p4){
    bool tag=0;
    double r1=multi(p3,p4,p1),r2=multi(p3,p4,p2);
    double r3=multi(p1,p2,p3),r4=multi(p1,p2,p4);
    if(r1*r2<eps&&r3*r4<eps) tag=1; //如果是端点接触相交 r1*r2趋近于0   tag=1 
    return tag;
}
int main()
{
    //freopen("cin.txt","r",stdin);
    int n;
    while(cin>>n){  
        point u,v;
        for(int i=0;i<n;i++)  {
            scanf("%lf%lf%lf%lf",&eg[i].u.x,&eg[i].u.y,&eg[i].v.x,&eg[i].v.y);
        }

        scanf("%lf%lf",&eg[n].u.x,&eg[n].u.y);
        if(n==0){
            puts("Number of doors = 1");
            continue;
        }
        int ans=n;
        for(int i=0;i<n;i++){  //就选择交点作为另一个端点
            eg[n].v.x=eg[i].u.x;
            eg[n].v.y=eg[i].u.y;
            int sum=0;
            for(int j=0;j<n;j++){
                if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v))  sum++;
            }
            ans=ans<sum?ans:sum;
            eg[n].v.x=eg[i].v.x;
            eg[n].v.y=eg[i].v.y;
            sum=0;
            for(int j=0;j<n;j++){
                if(cross(eg[n].u,eg[n].v,eg[j].u,eg[j].v))  sum++;
            }
            ans=ans<sum?ans:sum;
        }
        printf("Number of doors = %d\n",ans);
    }
    return 0;
}



你可能感兴趣的:(相交)