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));
}
}