poj1556

线段相交+最短路。
难点嘛。。
数组又开小了。。
g++得%.f输出。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int MAXM = 5000;
const int MAXN = 200;
const double EPS = 1e-4;
struct Point
{
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}

    double getDis(Point &rhs)
    {
        double xx = x - rhs.x;
        xx *= xx;
        double yy = y - rhs.y;
        yy *= yy;
        return sqrt(xx + yy);
    }



    double x, y;
};

Point operator -(Point lhs, Point rhs)
{
    Point ret = Point(lhs.x - rhs.x, lhs.y - rhs.y);
    return ret;
}

double operator ^(Point lhs, Point rhs)
{
    double ret = lhs.x * rhs.y - lhs.y * rhs.x;
    return ret;
}

bool isCross(Point &a, Point &b, Point &c, Point &d)
{
    if(min(a.x, b.x) <= max(c.x, d.x) &&
        min(a.y, b.y) <= max(c.y, d.y) &&
        min(c.x, d.x) <= max(a.x, b.x) &&
        min(c.y, d.y) <= max(a.y, b.y))
    {
        double u, v, w, z;
        u = (c - a) ^ (b - a);
        v = (d - a) ^ (b - a);
        w = (a - c) ^ (d - c);
        z = (b - c) ^ (d - c);
        if(u * v <= EPS && w * z <= EPS) return true;
    }
    return false;
}

Point point[MAXN];

int cnt;

struct Edge
{
    int to, next;
    double dis;

    Edge() {};
    Edge(int _to, int _next, double _dis): to(_to), next(_next), dis(_dis) {}
};

Edge edge[MAXM];
int total, head[MAXN];

int n;


void init()
{
    total = 0;
    cnt = -1;
    memset(head, 0, sizeof(head));
}


bool vis[MAXN];
double dis[MAXN];
struct cmp
{
    bool operator() (int a, int b)
    {
        return dis[a] > dis[b];
    }
};
double dijkstra(int op, int end)
{
    memset(vis, 0, sizeof(vis));
    memset(dis, 0x43, sizeof(dis));
    priority_queue<int, std::vector<int>, cmp> q;

    dis[op] = 0.0;
    q.push(op);
    while(!q.empty())
    {
        int u = q.top();
        q.pop();
        if(vis[u]) continue;
        vis[u] = true;

        for(int i = head[u]; i; i = edge[i].next)
        {
            int v = edge[i].to;
            if(!vis[v] && dis[u] + edge[i].dis < dis[v])
            {
                dis[v] = dis[u] + edge[i].dis;
                q.push(v);
            }
        }
    }
    return dis[end];
}

void addStart(int op, int ed)
{
    for(int i = 0; i < n; ++i)
    {
        for(int ii = i * 6 + 1; ii < (i + 1) * 6 - 1; ++ii)
        {
            bool cross = false;
            for(int jj = 0; jj < i * 6; jj += 2)
            {
                if(isCross(point[jj], point[jj + 1], point[op], point[ii]))
                {
                    cross = true;
                    break;
                }
            }
            if(!cross)
            {
                edge[++total] = Edge(ii, head[op], point[op].getDis(point[ii]));
                head[op] = total;
            }
        }
    }

    bool cross = false;
    for(int k = 0; k < n * 6; k += 2)
    {
        if(isCross(point[op], point[ed], point[k], point[k + 1]))
        {
            cross = true;
            break;
        }
    }
    if(!cross)
    {
        edge[++total] = Edge(ed, head[op], point[op].getDis(point[ed]));
        head[op] = total;
    }
}

void addEnd(int ed)
{
    for(int i = 0; i < n; ++i)
    {
        for(int ii = i * 6 + 1; ii < (i + 1) * 6 - 1; ++ii)
        {
            bool cross = false;
            for(int jj = n * 6 - 2; jj >= (i + 1) * 6; jj -= 2)
            {
                if(isCross(point[jj], point[jj + 1], point[ed], point[ii]))
                {
                    cross = true;
                    break;
                }
            }
            if(!cross)
            {
                edge[++total] = Edge(ed, head[ii], point[ed].getDis(point[ii]));
                head[ii] = total;
            }
        }
    }
}

void addMid()
{
    for(int i = 0; i < n; ++i)
    {
        for(int ii = i * 6 + 1; ii < (i + 1) * 6 - 1; ++ii)
        {
            for(int j = i + 1; j < n; ++j)
            {
                for(int jj = j * 6 + 1; jj < (j + 1) * 6 - 1; ++jj)
                {
                    bool cross = false;
                    for(int k = (i + 1) * 6; k < j * 6; k += 2)
                    {
                        if(isCross(point[ii], point[jj], point[k], point[k + 1]))
                        {
                            cross = true;
                            break;
                        }
                    }
                    if(!cross)
                    {
                        edge[++total] = Edge(jj, head[ii], point[ii].getDis(point[jj]));
                        head[ii] = total;
                    }
                }
            }
        }

    }
}

int main()
{
    Point src = Point(0, 5), sink = Point(10, 5);
    double x, y;
    while(scanf("%d", &n) && n != -1)
    {
        init();
        for(int i = 1; i <= n; ++i)
        {
            scanf("%lf", &x);
            point[++cnt] = Point(x, 0.0);
            for(int j = 1; j <= 4; ++j)
            {
                scanf("%lf", &y);
                point[++cnt] = Point(x, y);
            }
            point[++cnt] = Point(x, 10.0);
        }
        point[++cnt] = src;
        point[++cnt] = sink;
        addStart(cnt - 1, cnt);
        addEnd(cnt);
        addMid();
        printf("%.2f\n", dijkstra(cnt - 1, cnt));
    }
}