POJ 1556 The Doors(线段与线段是否相交,建图最短路,包含模板)

POJ 1556 The Doors(线段与线段是否相交,建图最短路,包含模板)

思路:这道题要想到,走端点一定是最短的。所以我们可以将这道题看成一个图,看看端点与端点之间是否能够构称边。这时候我们就要穷举任意两点,如果两点之间没有线段隔着,说明可以联通,这时候添加一条边。添加完之后跑一遍dijkstra算法,就跑出来了。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include <cstdio>
using namespace std;
#define ll long long
struct Point
{
    double x,y;
    Point(double x= 0, double y = 0):x(x),y(y){}
};
typedef Point Vector;
const int INF = 0x3f3f;
Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator *(Vector A, double p)
{
    return Vector(A.x*p, A.y*p);
}
Vector operator +(Vector A, Vector B){
    return Vector(A.x+B.x, A.y+B.y);
}
Vector operator /(Vector A, double p){return Vector(A.x/p, A.y/p);}
double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y;}
double Length(Vector A){ return sqrt(Dot(A, A));}
double Cross(Vector A, Vector B){return A.x*B.y-A.y*B.x;}
double dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
const double eps = 1e-6;
int sgn(double x){
    if(fabs(x) < eps)
        return 0;
    if(x < 0)
        return -1;
    return 1;
}
struct Line{
    Point v, p;
    Line(){}
    Line(Point v, Point p):v(v), p(p){}
    Point point(double t){
        return v+(p-v)*t;//·µ»ØµãP = v + (p - v)*t
    }
}line[1050];
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
    double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}

const int M = 200;
struct Edge
{
    int from, to;
    double dist;
    Edge(int u, int v, double d):from(u),to(v),dist(d) {}
};
struct HeapNode
{
    double d;
    int u;
    HeapNode(double d, int u):d(d),u(u){}
    bool operator< (const HeapNode & rhs) const{
        return d >rhs.d;
    }
};

struct Dijkstra
{
    int n, m;
    vector<Edge>edges;
    vector<int>G[M];
    bool done[M];
    double dis[M]; //距离
    int p[M];   //最短路中的上一条弧

    void init(int n)
    {
        this ->n = n;
        for(int i = 0; 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 dijkstra(int s)
    {
        priority_queue<HeapNode>Q;
        for(int i  = 0; i<n; i++) dis[i] = INF;
        dis[s] = 0;
        memset(done, 0, sizeof(done));
        Q.push(HeapNode(0,s));

        while(!Q.empty())
        {
            HeapNode x = Q.top(); Q.pop();
            int u = x.u;
            if(done[u]) continue;

            done[u] = true;
            for(int i = 0; i<G[u].size(); i++)
            {
                Edge &e = edges[G[u][i]];
                if(dis[e.to] > dis[u] + e.dist)
                {
                    dis[e.to] = dis[u] + e.dist;
                    p[e.to] =edges[ G[u][i]].from;
                    Q.push(HeapNode(dis[e.to], e.to));
                }
            }
        }
    }
};


int main()
{
    int n;

    while(scanf("%d",&n)!=EOF)

    {

        if(n == -1)
            return 0;
        Dijkstra dj;
        dj.init(199);
        int cnt = 0;
        int ct = -1;
        Point p[10000];

        p[++ct] = Point(0,5);
        for(int i = 1;i<=n;i++)
        {
            double a,b,c,d,e;
            scanf("%lf%lf%lf%lf%lf", &a, &b, &c, &d, &e);
            line[++cnt] = Line(Point(a,0), Point(a,b));
            line[++cnt] = Line(Point(a,c), Point(a,d));
            line[++cnt] = Line(Point(a,e), Point(a,10));
            p[++ct] = Point(a,b);
            p[++ct] = Point(a,c);
            p[++ct] = Point(a,d);
            p[++ct] = Point(a,e);

        }
        p[++ct]=Point(10, 5);
        bool flag = true;

	    double mat[M][M];
        for(int i = 0;i<=ct;i++)
        {
            for(int j = i+1;j<=ct;j++)
            {
                flag = true;
                for(int k = 1;k<=cnt;k++)
                {

                    if(SegmentProperIntersection(p[i],p[j],line[k].v,line[k].p))
                    {
                        flag = false;
                        break;
                    }
                }
                if(flag)
                {
                    //cout<<i<<j<<dis(p[i],p[j])<<endl;
                    dj.AddEdge(i, j, dis(p[i],p[j]));
                    dj.AddEdge(j, i, dis(p[i],p[j]));
                }
            }
        }

        dj.dijkstra(0);
        printf("%.2lf\n",dj.dis[ct]);

    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值