The Doors POJ - 1556 判断线段相交+最短路径

题意:给你一个10*10的正方形的盒子,里面有一些线段,让你求从坐标(0,5)出发到坐标(10,5)的最短路径。

思路:判断任意两条线段的端点连线与其它线段是否有交点即可。最后用一个最短路径模板就可以了。

补充两知识点:

① 快速排斥实验:如果两条边所在矩形不相交则一定不相交,即满足

设线段a为(x1,y1)--(x2,y2)               线段b为(x3,y3)--(x4,y4)

这是判断可能相交的条件:min(x1,x2)<=max(x3,x4)  &&  min(x3,x4)<=max(x1,x2)  &&  min(y1,y2)<=max(y3,y4) &&  min(y3,y4)<=max(y1,y2) 才可能相交。

②跨立实验:此链接有详解:https://blog.csdn.net/HXX904/article/details/116273561?spm=1001.2014.3001.5501

最后用Dijstra跑一遍最短路就OK啦。

AC代码:

#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1e-8
typedef long long ll;
const int N=100;
const double inf=1e8;
int n;
double s[N][N],book[N];
double dis[N];
struct node
{
    double x,y;
} p[N];
int pan(double a,double b,double c,double d,double a1,double b1,double c1,double d1)
{
    if(!(min(a,c)<=max(a1,c1)&&min(a1,c1)<=max(a,c)&&min(b,d)<=max(b1,d1)&&min(b1,d1)<=max(b,d)))//快速排斥实验
        return 0;
    double u=((c-a)*(d1-b)-(d-b)*(c1-a))*((c-a)*(b1-b)-(d-b)*(a1-a));
    double v=((c1-a1)*(b-b1)-(d1-b1)*(a-a1))*((c1-a1)*(d-b1)-(d1-b1)*(c-a1));
    if(u>=0.0||v>=0.00)//跨立实验  利用叉乘判断
        return 0;
    return 1;
}
double solve(double a,double b,double c,double d)//判断是否能直接到达,可以的话,计算距离
{
    double a1,b1,c1,d1;
    for(int i=0; i<n; i++)
    {
        a1=c1=p[4*i+1].x;
        b1=0,d1=p[4*i+1].y;
        if(pan(a,b,c,d,a1,b1,c1,d1))return inf;
        b1=p[4*i+2].y,d1=p[4*i+3].y;
        if(pan(a,b,c,d,a1,b1,c1,d1))return inf;
        b1=p[4*i+4].y,d1=10;
        if(pan(a,b,c,d,a1,b1,c1,d1))return inf;
    }
    return sqrt((c-a)*(c-a)+(d-b)*(d-b));
}
void dijstra()
{
    memset(book,0,sizeof(book));
    for(int i=0; i<=99; i++)dis[i]=s[0][i];
    dis[0]=0;
    for(int i=0; i<=4*n+1; i++)
    {
        double minn=inf;
        int k;
        for(int j=0; j<=4*n+1; j++)
            if(!book[j]&&dis[j]<minn)
                minn=dis[k=j];
        book[k]=1;
        for(int j=0; j<=4*n+1; j++)
            if(dis[j]>dis[k]+s[k][j])
                dis[j]=dis[k]+s[k][j];
    }
}

int main()
{
    while(scanf("%d",&n)&&n!=-1)
    {
        p[0].x=0,p[0].y=5;
        for(int i=0; i<n; i++)
        {
            double x,y1,y2,y3,y4;
            cin>>x>>y1>>y2>>y3>>y4;
            p[i*4+1].x=x,p[i*4+1].y=y1;
            p[i*4+2].x=x,p[i*4+2].y=y2;
            p[i*4+3].x=x,p[i*4+3].y=y3;
            p[i*4+4].x=x,p[i*4+4].y=y4;
        }
        p[n*4+1].x=10,p[n*4+1].y=5;
        for(int i=0; i<=4*n+1; i++)
        {
            s[i][i]=0.0;
            for(int j=i+1; j<=4*n+1; j++)
                s[i][j]=s[j][i]=solve(p[i].x,p[i].y,p[j].x,p[j].y);
        }
        dijstra();
        printf("%.2f\n",dis[4*n+1]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值