2018.07.06 POJ1556 The Doors(最短路)

The Doors
Time Limit: 1000MS Memory Limit: 10000K
Description
You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length.
这里写图片描述
Input
The input data for the illustrated chamber would appear as follows.
2
4 2 7 8 9
7 3 4.5 6 7
The first line contains the number of interior walls. Then there is a line for each such wall, containing five real numbers. The first number is the x coordinate of the wall (0 < x < 10), and the remaining four are the y coordinates of the ends of the doorways in that wall. The x coordinates of the walls are in increasing order, and within each line the y coordinates are in increasing order. The input file will contain at least one such set of data. The end of the data comes when the number of walls is -1.
Output
The output should contain one line of output for each chamber. The line should contain the minimal path length rounded to two decimal places past the decimal point, and always showing the two decimal places past the decimal point. The line should contain no blanks.
Sample Input
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
Sample Output
10.00
10.06
Source
Mid-Central USA 1996

一道相对来说偏综合的简单题,我们将墙拆成两个点,然后这道题的样例图示给了我们很好的思路:样例图示中整张图被巧妙地搞成了一张类分层图,而题目又让我们求从 s s t的最短路径,题目中还巧妙地回避了有负边权的情况。既然这样,我们怎么可能不用 dijstra d i j s t r a 来跑最短路呢?然后就是建图的问题了,最开始我想到的是相邻两层之间建边,但仔细一想这样会 gg g g ,于是改进一下建边的方法,对于每一个点,我们将它跟在它后面出现的点连边,边权的处理也很简单。如果两点之间可以直接抵达没有墙的间隔,那么直接将边权赋值为两点间的距离即可,如果有墙的间隔,我们不建边或者将边权赋成极大值,建完图之后跑最短路计算就行了。

然后还有一个坑点就是 POJ P O J 上用 g++ g + + 的话 double d o u b l e 的输出只能用 (本蒟蒻因为这一点挂了 10+ 10 + 次)

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define N 100005
#define eps 1e-15 
using namespace std;
struct pot{double x,y;}p[N];
struct edge{int v,next;double w;}e[N];
struct line{pot a,b;}l[N];
struct heap{int u;double w;};
inline bool operator<(heap a,heap b){return a.w>b.w;}
int n,first[N],cnt=0,s,t,tot=0,totx=0;
double d[N];
bool vis[N];
inline void add(int u,int v,double w){
    e[++cnt].v=v;
    e[cnt].next=first[u];
    e[cnt].w=w;
    first[u]=cnt;
}
inline double dijsktra(){
    priority_queue<heap>q;
    for(int i=0;i<=tot;++i)d[i]=10000000000.0,vis[i]=false;
    d[s]=0.0;
    q.push((heap){s,d[s]});
    while(!q.empty()){
        heap x=q.top();
        q.pop();
        if(vis[x.u])continue;
        vis[x.u]=true;
        for(int i=first[x.u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(d[v]>d[x.u]+e[i].w){
                d[v]=d[x.u]+e[i].w;
                q.push((heap){v,d[v]});
            }
        }
    }
    return d[t];
}
inline double dis(pot a,pot b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline pot operator-(pot a,pot b){return (pot){a.x-b.x,a.y-b.y};}
inline double cross(pot a,pot b){return a.x*b.y-a.y*b.x;}
inline int sign(double x){return (x>eps)-(x<-eps);}
inline bool pd(pot a,pot b,pot c,pot d){return sign(cross(a-c,b-c))*sign(cross(a-d,b-d))<0;}
inline bool check(int a,int b){
    for(int i=1;i<=totx;++i)if(pd(p[a],p[b],l[i].a,l[i].b)&&pd(l[i].a,l[i].b,p[a],p[b]))return false;
    return true;
}
int main(){
    p[s=0].x=0.0,p[s].y=5.0;
    while(scanf("%d",&n)&&n!=-1){
        memset(first,-1,sizeof(first));
        cnt=0,tot=0,totx=0;
        for(int i=1;i<=n;++i){
            double x0,y1,y2,y3,y4;
            scanf("%lf%lf%lf%lf%lf",&x0,&y1,&y2,&y3,&y4);
            p[++tot].x=x0,p[tot].y=0.0;
            p[++tot].x=x0,p[tot].y=y1;
            p[++tot].x=x0,p[tot].y=y2;
            p[++tot].x=x0,p[tot].y=y3;
            p[++tot].x=x0,p[tot].y=y4;
            p[++tot].x=x0,p[tot].y=10.0;
            l[++totx].a=(pot){x0,0.0},l[totx].b=(pot){x0,y1};
            l[++totx].a=(pot){x0,y2},l[totx].b=(pot){x0,y3};
            l[++totx].a=(pot){x0,y4},l[totx].b=(pot){x0,10.0};
        }
        p[t=++tot].x=10.0,p[t].y=5.0;
        for(int i=s;i<=t;++i)
            for(int j=i+1;j<=t;++j)
                if(check(i,j))add(i,j,dis(p[i],p[j]));
                else add(i,j,10000000000.0);
        printf("%.2lf\n",dijsktra());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值