poj The Doors (SPFA+判断两线段是否相交)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83586689

题目链接:poj 1556

题意:房间里有n堵墙,每面墙上有两扇门,从(0, 5)走到(10, 5),中间有一些门,走的路是直线,问最短的距离。

题解:建图,再求个最短路就行了,这题主要难在建图。

参考博客:https://www.cnblogs.com/Running-Time/p/4906367.html

https://blog.csdn.net/hq572241670/article/details/41550849?locationNum=2&fps=1

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

using namespace std;

#define INF 0x3f3f3f3f
const int maxn=300;

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 dot(point A,point B) { return A.x*B.x+A.y*B.y;}
double Cross(point A,point B) { return A.x*B.y-A.y*B.x;}
double Length(point A) {return sqrt(dot(A,A));}


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表示,相交于端点也认定为相交
    if(dcmp(c1*c2)>0&&dcmp(c3*c4)>0) return true;

    return false;
}


vector <pair<int,double> > G[maxn]; ///存储图
int vis[maxn],tot,Start,End;///SPFA
double dis[maxn];

point p[maxn]; ///存储点

void SPFA()
{
    for(int i=1;i<=tot;i++) dis[i]=1000;

    memset(vis,0,sizeof(vis));
//    printf("%.2f\n",dis[End]);
    queue<int> Q;
    Q.push(Start);
    vis[Start]=1;dis[Start]=0;

    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();

        vis[u]=0;

        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i].first;
            double w=G[u][i].second;

            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                if(!vis[v]) {
                    Q.push(v);
                    vis[v]=1;
                }
            }
        }
    }

}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n!=-1)
    {

        tot=0;
        p[tot++]=point(0,5);

        double x,y1,y2,y3,y4;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);

            p[tot++]=point(x,y1);
            p[tot++]=point(x,y2);
            p[tot++]=point(x,y3);
            p[tot++]=point(x,y4);

        }
        p[tot++]=point(10,5);
        for(int i=0;i<=tot;i++) G[i].clear();

        for(int i=0;i<tot;i++) ///枚举点,start
        {
            for(int j=i+1;j<tot;j++) ///end
            {
                if(dcmp(p[i].x-p[j].x)==0) continue; ///两点都在同一块墙
                bool flag=true;

                for(int k=i+1;k<j;k++) ///判断有没有墙阻隔点(i,j)
                {
                    if(dcmp(p[i].x-p[k].x)==0||dcmp(p[j].x-p[k].x)==0) ///阻隔墙不能在两点对应的墙
                        continue;

                    if(k%4==1){ ///第一块
                        if(isCross(p[i],p[j],p[k],point(p[k].x,0))){
                        flag=false;break;
                        }

                    }
                    else if(k%4==0){ ///第四块
                        if(isCross(p[i],p[j],p[k],point(p[k].x,10))){
                            flag=false;break;

                        }
                    }
                    else if(k%4==2){ ///第二块
                        if(isCross(p[i],p[j],p[k],p[k+1])){
                            flag=false;break;

                        }
                    }
                    else if(k%4==3){ ///第三块
                        if(isCross(p[i],p[j],p[k-1],p[k])){
                            flag=false;break;

                        }
                    }
                }
                if(flag) {
                    G[i].push_back(make_pair(j,Length(p[j]-p[i]))); ///建立双向边
                    G[j].push_back(make_pair(i,Length(p[j]-p[i])));
                }
            }
        }

        Start=0;End=tot-1; ///初始化
        SPFA();

        printf("%.2f\n",dis[End]);
    }
    return 0;
}



/*
i=0,j=1
i=0,j=2
i=0,j=3
i=0,j=4
i=0,j=5
i=1,j=5
i=2,j=5
i=3,j=5
i=4,j=5

i=0,j=1
i=0,j=2
i=0,j=3
i=0,j=4
i=0,j=5
i=0,j=6
i=0,j=7
i=0,j=8
i=1,j=5
i=1,j=6
i=1,j=7
i=1,j=8
i=1,j=9
i=2,j=5
i=2,j=6
i=2,j=7
i=2,j=8
i=2,j=9
i=3,j=5
i=3,j=6
i=3,j=7
i=3,j=8
i=3,j=9
i=4,j=5
i=4,j=6
i=4,j=7
i=4,j=8
i=4,j=9
i=5,j=9
i=6,j=9
i=7,j=9
i=8,j=9
*/

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/83586689