zoukankan      html  css  js  c++  java
  • POJ 1556 The Doors(点到线段的距离+最短路)

    The Doors
    Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

    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. 


    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

    题意:在平面直角坐标系上有一个10*10的正方形房间,房间中有n堵平行y方向的墙,每堵墙上有两扇门,

    问从房间最左边的(0,5)处,通过门,到达房间最右边的(10,5)处的最短距离

    思路:构造一个图,对图求最短距。

    构图:每扇门由两个端点构成,求出每堵墙上的门的端点到其他墙上的门的端点的距离(前提:这两个点能够直接相连不撞墙),当然,起点终点也要参与上述的求距离构图过程。

               之后,再对构好的图求最短距即可。


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    double g[100][100], dist[100];
    bool visit[100];
    int n, t_id; //n为墙数,t_id为终点在图中的编号
    
    const double eps = 1e-8;
    const double inf = 999999999;
    
    /*door[i][j][k]表示第i堵墙的j扇门的第k端点
      s为起点,t为终点
    */
    struct Point {
        double x, y;
    } door[20][2][2], s, t;
    
    //叉积
    double multi(Point p1, Point p2, Point p0) {
        return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);
    }
    
    //判断线段ab与直线cd是否相交,过端点也算相交
    bool cross(Point a, Point b, Point c, Point d) {
        if (multi(a, d, c) * multi(b, d, c) > eps) return false;
        return true;
    }
    
    //求两点距离
    double dis(Point a, Point b) {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    //判断两点是否能够直接相连不撞墙
    bool judge(int i, int j, Point a, Point b) {
         for (; i <= j; i++)
             if (cross(door[i][0][0], door[i][0][1], a, b) == false && cross(door[i][1][0], door[i][1][1], a, b) == false)
                return false;
         return true;
    }
    
    //构图:将不同墙上的门之间的距离构造进图
    void make_map() {
         int i, j, k, l, p, q, x, y;
    
         for (i = 0; i < n-1; i++)
             for (j = 0; j < 2; j++)
                for (k = 0; k < 2; k++) {
                    x = 4*i+2*j+k+1;
                    for (l = i + 1; l < n; l++)
                        for (p = 0; p < 2; p++)
                            for (q = 0; q < 2; q++) {
                                y = 4*l+2*p+q+1;
                                if (judge(i+1, l-1, door[i][j][k], door[l][p][q]))
                                    g[x][y] = dis(door[i][j][k], door[l][p][q]);
                            }
                }
    }
    
    //求最短距
    double Dikstra() {
        int i, j, cur;
        double tmp;
    
        memset(visit, false, sizeof (visit));
        for (i = 1; i <= t_id; i++) dist[i] = inf;
        dist[0] = 0;
        for (i = 0; i <= t_id; i++) {
            tmp = inf;
            cur = -1;
            for (j = 0; j <= t_id; j++)
                if (!visit[j] && dist[j] < tmp) {
                    tmp = dist[j];
                    cur = j;
                }
            visit[cur] = true;
            if (cur == t_id) break;
            for (j = 0; j <= t_id; j++) {
                if (!visit[j] && g[cur][j] > eps && dist[cur] + g[cur][j] + eps < dist[j])
                    dist[j] = dist[cur] + g[cur][j];
            }
        }
        return dist[t_id];
    }
    
    int main()
    {
        double x, y1, y2, y3, y4;
        int i, j, k;
    
        //初始化起点终点坐标
        s.x = 0; s.y = 5;
        t.x = 10; t.y = 5;
        while (scanf ("%d", &n) && n != -1) {
            for (i = 0; i < n; i++) {
                scanf ("%lf%lf%lf%lf%lf", &x, &y1, &y2, &y3, &y4);
                door[i][0][0].x = door[i][0][1].x = door[i][1][0].x = door[i][1][1].x = x;
                door[i][0][0].y = y1; door[i][0][1].y = y2;
                door[i][1][0].y = y3; door[i][1][1].y = y4;
            }
            memset(g, 0, sizeof (g));
            t_id = 4 * n + 1; //求出终点在图中的编号
            if (judge(0, n-1, s, t)) { //r若起点终点可以直接相连,则这两点距离即为答案
                printf ("%.2lf
    ", dis(s, t));
                continue;
            }
            int id;
            //将起点和终点与中间的墙上的门的距离构造进图
            for (i = 0; i < n; i++) {
                for (j = 0; j < 2; j++) {
                    for (k = 0; k < 2; k++) {
                        id = 4*i+2*j+k+1; //求出门上的点在图中的编号
                        if (judge(0, i-1, s, door[i][j][k])) g[0][id] = dis(s, door[i][j][k]);
                        if (judge(i+1, n-1, door[i][j][k], t)) g[id][t_id] = dis(door[i][j][k], t);
                    }
                }
            }
            make_map();
            printf ("%.2lf
    ", Dikstra());
        }
        return 0;
    }
    








    /************************************************************
     * Author        : kuangbin
     * Email         : kuangbin2009@126.com 
     * Last modified : 2013-07-14 10:47
     * Filename      : POJ1556TheDoors.cpp
     * Description   : 
     * *********************************************************/
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    
    using namespace std;
    
    const double eps = 1e-8;
    int sgn(double x)
    {
        if(fabs(x) < eps)return 0;
        if(x < 0) return -1;
        else return 1;
    }
    struct Point
    {
        double x,y;
        Point(){}
        Point(double _x,double _y)
        {
            x = _x;y = _y;
        }
        Point operator -(const Point &b)const
        {
            return Point(x - b.x,y - b.y);
        }
        double operator ^(const Point &b)const
        {
            return x*b.y - y*b.x;
        }
        double operator *(const Point &b)const
        {
            return x*b.x + y*b.y;
        }
    };
    struct Line
    {
        Point s,e;
        Line(){}
        Line(Point _s,Point _e)
        {
            s = _s;e = _e;
        }
    };
    //判断线段相交
    bool inter(Line l1,Line l2)
    {
        return 
            max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
            max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
            max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
            max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
            sgn((l2.s-l1.s)^(l1.e-l1.s))*sgn((l2.e-l1.s)^(l1.e-l1.s)) <= 0 &&
            sgn((l1.s-l2.s)^(l2.e-l2.s))*sgn((l1.e-l2.s)^(l2.e-l2.s)) <= 0;
    }
    double dist(Point a,Point b)
    {
        return sqrt((b-a)*(b-a));
    }
    const int MAXN = 100;
    Line line[MAXN];
    double dis[MAXN][MAXN];
    const double INF = 1e20;
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        int n;
        double x,y1,y2,y3,y4;
        while(scanf("%d",&n) == 1)
        {
            if(n == -1) break;
            for(int i = 1;i <= n;i++)
            {
                scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
                line[2*i-1] = Line(Point(x,y1),Point(x,y2));
                line[2*i] = Line(Point(x,y3),Point(x,y4));
            }
            for(int i = 0;i <= 4*n+1;i++)
                for(int j = 0;j <= 4*n+1;j++)
                {
                    if(i == j)dis[i][j] = 0;
                    else dis[i][j] = INF;
                }
            for(int i = 1;i <= 4*n;i++)
            {
                int lid = (i+3)/4;
                bool flag = true;
                Point tmp;
                if(i&1)tmp = line[(i+1)/2].s;
                else tmp = line[(i+1)/2].e;
                for(int j = 1;j < lid;j++)
                    if(inter(line[2*j-1],Line(Point(0,5),tmp)) == false
                            && inter(line[2*j],Line(Point(0,5),tmp)) == false)
                        flag = false;
                if(flag)dis[0][i] =dis[i][0] = dist(Point(0,5),tmp);
                flag = true;
                for(int j = lid+1;j <= n;j++)
                    if(inter(line[2*j-1],Line(Point(10,5),tmp)) == false
                            && inter(line[2*j],Line(Point(10,5),tmp)) == false)
                        flag = false;
                if(flag)dis[i][4*n+1] =dis[4*n+1][i] = dist(Point(10,5),tmp);
            }
            for(int i = 1;i <= 4*n;i++)
                for(int j = i+1;j <=4*n;j++)
                {
                    int lid1 = (i+3)/4;
                    int lid2 = (j+3)/4;
                    bool flag = true;
                    Point p1,p2;
                    if(i&1)p1 = line[(i+1)/2].s;
                    else p1 = line[(i+1)/2].e;
                    if(j&1)p2 = line[(j+1)/2].s;
                    else p2 = line[(j+1)/2].e;
                    for(int k = lid1+1;k < lid2;k++)
                        if(inter(line[2*k-1],Line(p1,p2)) == false
                                && inter(line[2*k],Line(p1,p2)) == false)
                            flag = false;
                    if(flag) dis[i][j] = dis[j][i] = dist(p1,p2);
                }
            bool flag = true;
            for(int i = 1;i <= n;i++)
                if(inter(line[2*i-1],Line(Point(0,5),Point(10,5))) == false
                        && inter(line[2*i],Line(Point(0,5),Point(10,5))) == false)
                    flag = false;
            if(flag)dis[0][4*n+1] = dis[4*n+1][0] = 10;
            for(int k = 0;k <= 4*n+1;k++)
                for(int i = 0;i <= 4*n+1;i++)
                    for(int j = 0;j <= 4*n+1;j++)
                        if(dis[i][k] + dis[k][j] < dis[i][j])
                            dis[i][j] = dis[i][k] + dis[k][j];
            printf("%.2lf
    ",dis[0][4*n+1]);
        }
        
        return 0;
    }





  • 相关阅读:
    java工程师要求
    系统架构设计师知识模块
    Mybatis使用训练
    项目—视频直播系统
    [数算]概率
    查看镜像文件
    Hadoop启动命令
    Hadoop启动命令
    HDFS设置配额管理
    HDFS设置配额管理
  • 原文地址:https://www.cnblogs.com/zswbky/p/6717938.html
Copyright © 2011-2022 走看看