[vijos1013] 强墙 /[uva393] 房间最短路问题

题目描述

在一个长宽均为10,入口出口分别为(0,5)、(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经。

输入格式

第一排为n(n<=20),墙的数目。
接下来n排,每排5个实数x,a1,b1,a2,b2。
x表示墙的横坐标(所有墙都是竖直的),a1-b1和a2-b2之间为空缺。
a1、b1、a2、b2保持递增,x1-xn也是递增的。

输出格式

输出最短距离,保留2位小数。

样例数据

样例输入

2
4 2 7 8 9
7 3 4.5 6 7

样例输出

10.06

题目分析

比较难建图的一道题
先把所有墙建成线段,将墙的两端作为结点建图,在图中所有结点间建边(但是边不能与墙相交),边权为欧几里德距离
然后跑一次dijkstra就可以了
代码写的有点智障

源代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
struct Point {
    double x,y;
};
double Dist(Point a,Point b) {
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Vector {
    double x,y;
};
Vector operator - (Point a,Point b) {
    Vector c;
    c.x=b.x-a.x;
    c.y=b.y-a.y;
    return c;
}
double Cross(Vector a,Vector b) { //叉积
    return a.x*b.y-b.x*a.y;
}
bool Segment_Intersect(Point A,Point B,Point C,Point D) { //判断两线段是否相交
    return (Cross((C-A),(D-A))*Cross((C-B),(D-B))<0)&&(Cross((A-C),(B-C))*Cross((A-D),(B-D))<0);
}
///////////////
const int maxn=20005; //数组范围
struct Edge { //前向星
    int from,to;
    double dist;
};
struct HeapNode {
    double d;
    int u; //u为当前结点
    bool operator < (HeapNode a) const {
        return d>a.d;
    }
};
struct Dijkstra {
    int n,m;
    vector edges; //邻接表
    vector<int> G[maxn]; //记录每个结点可以到达的结点
    bool vst[maxn];
    double dist[maxn];
    int path[maxn]; //使用path记录最短路
    void init(int n) {
        this->n=n;
        for(int i=1; i<=n; i++)G[i].clear();
        edges.clear();
    }
    void AddEdge(int from,int to,double dist) {
        edges.push_back((Edge) {
            from,to,dist
        });
        m=edges.size();
        G[from].push_back(m-1);
    }
    void main(int s) { //核心算法
        priority_queue Q;
        for(int i=1; i<=n; i++)dist[i]=1e10;
        dist[s]=0;
        path[s]=s;
        memset(vst,0,sizeof(vst));
        Q.push((HeapNode) {
            0,s
        });
        while(!Q.empty()) {
            HeapNode Now=Q.top();
            Q.pop();
            if(vst[Now.u])continue;
            vst[Now.u]=1;
            for(int i=0; i//边的信息
                int Next=e.to;
                if(dist[Next]>dist[Now.u]+e.dist) {
                    dist[Next]=dist[Now.u]+e.dist;
                    path[Next]=Now.u;
                    Q.push((HeapNode) {
                        dist[Next],Next
                    });
                }
            }
        }
    }
} ;
/////////////// 
Point Start[105],End[105],P[105]; //障碍
Dijkstra dij;
int n,cnt=0,cnt1=0;
int main() {
    scanf("%d",&n);
    P[++cnt1]=(Point) {
        0,5
    };
    P[++cnt1]=(Point) {
        10,5
    };
    for(int i=1; i<=n; i++) {
        double x,a1,b1,a2,b2;
        scanf("%lf%lf%lf%lf%lf",&x,&a1,&b1,&a2,&b2);
        Start[++cnt].x=x;
        Start[cnt].y=0;
        End[cnt].x=x;
        End[cnt].y=a1;
        Start[++cnt].x=x;
        Start[cnt].y=b1;
        End[cnt].x=x;
        End[cnt].y=a2;
        Start[++cnt].x=x;
        Start[cnt].y=b2;
        End[cnt].x=x;
        End[cnt].y=10;
        P[++cnt1]= (Point) {
            x,a1
        };
        P[++cnt1]= (Point) {
            x,b1
        };
        P[++cnt1]= (Point) {
            x,a2
        };
        P[++cnt1]= (Point) {
            x,b2
        };
    }
    dij.init(cnt1);
    for(int i=1; i<=cnt1; i++)
        for(int j=i+1; j<=cnt1; j++) {
            int bj=1;
            for(int k=1; k<=cnt; k++)
                if(Segment_Intersect(P[i],P[j],Start[k],End[k])) {
                    bj=0;
                    break;
                }
            if(bj==0)continue;
            dij.AddEdge(i,j,Dist(P[i],P[j]));
            dij.AddEdge(j,i,Dist(P[i],P[j]));
        }
    dij.main(1);
    printf("%0.2lf\n",dij.dist[2]);
    return 0;
}

你可能感兴趣的:(最短路径,计算几何)