POJ 1556 E

题意:给定n堵墙,现在要你从(0,5)走去(10,5)的最短距离

思路:刚开始还想模拟,就是从(0,5)走,每次x向右一格,然后判断有没和线段相交就可以。但是它的们有可能是小数形式给出的,这样就GG了(x--x+1中可能存在很多门)。正确的方法应该是建图,对于所有门,他们都有端点的,先把他们加入到图中,包括起点的话,一共有num个点吧。然后暴力判断e[i][j]是否能到达就可以,这里用线段相交就可以判断。然后floyd一下就好。bug点:门的端点不应该加进来,就是(x,0)、(x,10)这样的点不应该加入图中,因为那个是死角,不能出去了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const double eps = 1e-8;
const int maxn = 100+20;
bool same (double a,double b)
{
    return fabs(a-b)<eps;
}
struct coor
{
    double x,y;
    coor(){}
    coor(double xx,double yy):x(xx),y(yy){}
    double operator ^(coor rhs) const //计算叉积(向量积)
    {
        return x*rhs.y - y*rhs.x;
    }
    coor operator -(coor rhs) const //坐标相减,a-b得到向量ba
    {
        return coor(x-rhs.x,y-rhs.y);
    }
    double operator *(coor rhs) const //数量积
    {
        return x*rhs.x + y*rhs.y;
    }
    bool operator ==(coor rhs) const
    {
        return same(x,rhs.x)&&(y,rhs.y);//same的定义其实就是和eps比较
    }
}a[maxn];

struct Line
{
    coor point1,point2;
    Line(){}
    Line(coor xx,coor yy):point1(xx),point2(yy){}
    bool operator &(Line rhs) const //判断直线和rhs线段是否相交
    {
        //自己表示一条直线,然而rhs表示的是线段
        //思路,判断rhs线段上两个端点是否在this直线的同一侧即可,用一侧,就不相交
        coor ff1 = point2 - point1; //直线的方向向量
        return ( ((rhs.point1-point1)^ff1) * ((rhs.point2-point1)^ff1) ) <= 0;//符号不同或者有0,证明相交
    }
}LINE[maxn];


bool OnSegment (coor a,coor b,coor c) //判断点C是否在线段ab上
{
    double min_x = min(a.x,b.x), min_y = min(a.y,b.y);
    double max_x = max(a.x,b.x), max_y = max(a.y,b.y);
    if (c.x>=min_x && c.x<=max_x && c.y>=min_y && c.y<=max_y) return true;
    else return false;
}
bool SegmentIntersect (coor a,coor b,coor c,coor d)
{
    double d1 = (b-a)^(d-a); //direction(a,b,d);以a为起点,计算ab和ab的叉积
    double d2 = (b-a)^(c-a);
    double d3 = (d-c)^(a-c);
    double d4 = (d-c)^(b-c);
    if (d1*d2<0 && d3*d4<0) return true;
    else if (d1 == 0 && OnSegment(a,b,d)) return true;
    else if (d2 == 0 && OnSegment(a,b,c)) return true;
    else if (d3 == 0 && OnSegment(c,d,a)) return true;
    else if (d4 == 0 && OnSegment(c,d,b)) return true;
    else return false;
}

int n;
int all=0;
double dis (coor a,coor b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double e[maxn][maxn];
void work ()
{
    all = 0;
    int num=0;
    for (int i=1;i<=n;++i)
    {
        double aa,bb,cc,dd,ee;
        scanf("%lf%lf%lf%lf%lf",&aa,&bb,&cc,&dd,&ee);
        ++all;
        LINE[all].point1 = coor(aa,0); //a[++num]=coor(aa,0);
        LINE[all].point2 = coor(aa,bb);a[++num]=coor(aa,bb);

        ++all;
        LINE[all].point1 = coor(aa,cc);a[++num]=coor(aa,cc);
        LINE[all].point2 = coor(aa,dd);a[++num]=coor(aa,dd);

        ++all;
        LINE[all].point1 = coor(aa,ee);a[++num]=coor(aa,ee);
        LINE[all].point2 = coor(aa,10);//a[++num]=coor(aa,10);
    }
    a[++num]=coor(0,5);
    a[++num]=coor(10,5);
    //memset(e,0x3f,sizeof e);
    for (int i=1;i<=maxn-20;++i)
    {
        for (int j=1;j<=maxn-20;++j)
        {
            e[i][j]=100000000.0;
        }

    }
    for (int i=1;i<=num;++i)
    {
        for (int j=i+1;j<=num;++j)
        {
            int k;
            //if (same(a[j].y,0)||same(a[j].y,10)||same(a[i].y,0)||same(a[i].y,10)) continue;
            for (k=1;k<=all;++k)
            {
                if (LINE[k].point1==a[i]||LINE[k].point1==a[j]||LINE[k].point2==a[i]||LINE[k].point2==a[j]) continue;
                if (SegmentIntersect(a[i],a[j],LINE[k].point1,LINE[k].point2)) break;
            }
            if (k==all+1) e[i][j]=e[j][i]=dis(a[i],a[j]);
        }
    }
    for (int i=1;i<=num;++i)
    {
        for (int j=1;j<=num;j++)
        {
            for (int k=1;k<=num;++k)
            {
                if (e[j][k]>e[j][i]+e[i][k]) e[j][k]=e[j][i]+e[i][k];
            }
        }
    }
    printf ("%0.2f
",e[num-1][num]);
    //printf ("%0.2f
",e[num-1][1]);
    return;
}

int main()
{
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    while(scanf("%d",&n)!=EOF && n!=-1) work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5759919.html