poj 1556 The Doors (线段之间位置的判断+最短路)

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.
poj 1556 The Doors (线段之间位置的判断+最短路)_第1张图片
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

大致题意:放置了n个障碍墙,每个障碍墙上有两个门可以通过,告诉你每个障碍墙的门的坐标(即4个坐标),然后问你从点(0,5)到(10,5)的最短距离是多少。

思路:0<=n<=18,将每个障碍墙看成由三段障碍线构成,然后这些障碍线的端点加上起点和终点一共就4*n+2个点,假设起点为0,终点为4*n+1,我们将问题转化为求0号点到4*n+1号点的最短路。然后我们枚举两点做连线,如果与障碍线不冲突,那么该两点之间的距离即两个坐标点之间的距离,否则设为无穷大,然后用求最短路算法即可。

代码如下

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double INF=0x3f3f3f3f;

int dcmp(double x) 
{
    if(fabs(x)return 0;
    return x<0?-1: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.x + y*b.y;
    }
    double operator ^(const Point &b)const {
        return x*b.y - y*b.x;
    }
    int operator ==(const Point &b)const {
        if(dcmp(x-b.x)==0&&dcmp(y-b.y)==0)//如果两点相同返回0 
        return 0;
        else return 1;
    }
};
struct Line 
{
    Point a,b;
    Line() {}
    Line(Point _a,Point _b) 
    {
        a=_a;
        b=_b;
    }
};
const int N=100;
double dis[N][N];
Line line[N];
Point dian[N];

double dist(Point a,Point b) 
{
    return sqrt((b-a)*(b-a));//返回两个点之间的距离
}
double xmult(Point p0,Point p1,Point p2)//叉积 
{
    return (p1-p0)^(p2-p0);
}
bool inter(Line L1,Line L2)//判断两条线段是否相交,若相交返回1否则0 
{
    return
        max(L1.a.x,L1.b.x) >= min(L2.a.x,L2.b.x) &&
        max(L2.a.x,L2.b.x) >= min(L1.a.x,L1.b.x) &&
        max(L1.a.y,L1.b.y) >= min(L2.a.y,L2.b.y) &&
        max(L2.a.y,L2.b.y) >= min(L1.a.y,L1.b.y) &&
        dcmp((L2.a-L1.a)^(L1.b-L1.a))*dcmp((L2.b-L1.a)^(L1.b-L1.a)) <= 0 &&
        dcmp((L1.a-L2.a)^(L2.b-L2.a))*dcmp((L1.b-L2.a)^(L2.b-L2.a)) <= 0; 
}

int main() 
{
    int n;
    double x,y1,y2,y3,y4;
    while(1) 
    {
        scanf("%d",&n);
        if(n==-1)   break;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
            dian[4*i-3]=Point(x,y1);
            dian[4*i-2]=Point(x,y2);
            dian[4*i-1]=Point(x,y3);
            dian[4*i]=Point(x,y4);

            line[i*3-2]=Line(Point(x,0),Point(x,y1));
            line[i*3-1]=Line(Point(x,y2),Point(x,y3));
            line[i*3]=Line(Point(x,y4),Point(x,10)); 
        }
        dian[0]=Point(0,5);
        dian[4*n+1]=Point(10,5);

        for(int i=0;i<=4*n+1;i++)//枚举两个点连线 
        for(int j=i;j<=4*n+1;j++)
        {
            if(i==j||(dcmp(dian[i].x-dian[j].x)==0))//同一障碍墙上的点不考虑 
            {
                dis[i][j]=dis[j][i]=INF;
            }
            else 
            {
                Line L=Line(dian[i],dian[j]);
                int flag=1;
                for(int k=1;k<=3*n;k++)
                { 
                    if(L.a==line[k].a&&L.a==line[k].b&&L.b==line[k].a&&L.b==line[k].b)//注意要忽略掉所选的两个点本身所在的障碍线 
                    if(inter(L,line[k]))
                    {   
                        flag=0;
                        break;
                    }
                }
                if(flag)
                    dis[i][j]=dis[j][i]=dist(dian[i],dian[j]);
                else 
                    dis[i][j]=dis[j][i]=INF;
            }
        }

        for (int k = 0; k <= 4*n+1; k++)  //spfa求最短路
        for (int i = 0; i <= 4*n+1; i++)  
        for (int j = 0; j <= 4*n+1; j++)  
        {  
            if(dis[i][k]printf("%.2f\n",dis[0][4*n+1]);
    }
    return 0;
}

你可能感兴趣的:(计算&解析几何)