/* ID: espr1t TASK: KEYWORDS: */ #include #include #include #include using namespace std; FILE *in; FILE *out; typedef double wtype; const int MAX = 2004; const int INF = 1000000001; const double EPS = 0.000001; struct Point { double x, y; Point(double x_ = 0.0, double y_ = 0.0) : x(x_), y(y_) {} }; struct Edge { int to; double price; Edge(int to_ = -1, double price_ = 0.0) : to(to_), price(price_) {} bool operator < (const Edge& r) const { return price > r.price; } }; int n; Point a[MAX][2]; vector v[MAX]; wtype dotProduct(Point p1, Point p2) { return p1.x * p2.x + p1.y * p2.y; } wtype crossProduct(Point p1, Point p2) { return p1.x * p2.y - p1.y * p2.x; } Point createVector(Point p1, Point p2) { return Point(p2.x - p1.x, p2.y - p1.y); } wtype findDist(Point p1, Point p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } wtype findArea(Point p1, Point p2, Point p3) { return p1.x * p2.y + p2.x * p3.y + p3.x * p1.y - p1.x * p3.y - p2.x * p1.y - p3.x * p2.y ; } bool linesDoCross(Point a1, Point a2, Point b1, Point b2) { wtype area1, area2; area1 = findArea(a1, a2, b1); area2 = findArea(a1, a2, b2); if (area1 < 0 && area2 < 0) return false; if (area1 > 0 && area2 > 0) return false; area1 = findArea(b1, b2, a1); area2 = findArea(b1, b2, a2); if (area1 < 0 && area2 < 0) return false; if (area1 > 0 && area2 > 0) return false; if (fabs(area1) < EPS && fabs(area2) < EPS) { if (findDist(a1, b1) + findDist(a1, b2) <= findDist(b1, b2) + EPS) return true; if (findDist(a2, b1) + findDist(a2, b2) <= findDist(b1, b2) + EPS) return true; if (findDist(b1, a1) + findDist(b1, a2) <= findDist(a1, a2) + EPS) return true; if (findDist(b2, a1) + findDist(b2, a2) <= findDist(a1, a2) + EPS) return true; return false; } return true; } wtype getMinDist(Point p, Point l1, Point l2) { double dist = findDist(l1, l2); if (dist < EPS) return findDist(p, l1); Point v1 = createVector(l1, p); Point v2 = createVector(l1, l2); wtype product = fabs(crossProduct(v1, v2)); wtype ans = product / findDist(l1, l2); // Check if the point is beyond point l2 if (dotProduct(createVector(l1, l2), createVector(l2, p)) >= 0) return findDist(l2, p); // Check if the point is beyond point l1 if (dotProduct(createVector(l2, l1), createVector(l1, p)) >= 0) return findDist(l1, p); return ans; } double getDist(int node1, int node2) { if (linesDoCross(a[node1][0], a[node1][1], a[node2][0], a[node2][1])) return 0.0; double ret = INF; ret = min(ret, getMinDist(a[node1][0], a[node2][0], a[node2][1])); ret = min(ret, getMinDist(a[node1][1], a[node2][0], a[node2][1])); ret = min(ret, getMinDist(a[node2][0], a[node1][0], a[node1][1])); ret = min(ret, getMinDist(a[node2][1], a[node1][0], a[node1][1])); return ret; } double dijkstra(int src, int snk) { vector vis(n + 2, false); vector price(n + 2, INF); price[src] = 0.0; for (int iter = 0; iter < n + 2; iter++) { int node = -1; double best = INF + 1; for (int cand = 0; cand < n + 2; cand++) { if (!vis[cand] && price[cand] < best) { best = price[cand]; node = cand; } } if (node == -1) break; vis[node] = true; for (int i = 0; i < (int)v[node].size(); i++) { if (price[node] + v[node][i].price < price[v[node][i].to]) { price[v[node][i].to] = price[node] + v[node][i].price; } } } return price[snk]; } double solve() { for (int node1 = 0; node1 < n; node1++) { for (int node2 = node1 + 1; node2 < n; node2++) { double dist = getDist(node1, node2); v[node1].push_back(Edge(node2, dist)); v[node2].push_back(Edge(node1, dist)); //fprintf(stderr, "Distance from %d to %d: %lf\n", node1, node2, dist); } } int src = n, snk = n + 1; a[src][0] = Point(0, 1000), a[src][1] = Point(1000, 1000); a[snk][0] = Point(0, 0), a[snk][1] = Point(1000, 0); double dist = getDist(src, snk); v[src].push_back(Edge(snk, dist)); v[snk].push_back(Edge(src, dist)); for (int node = 0; node < n; node++) { double srcDist = getDist(src, node); v[src].push_back(Edge(node, srcDist)); v[node].push_back(Edge(src, srcDist)); double snkDist = getDist(snk, node); v[snk].push_back(Edge(node, snkDist)); v[node].push_back(Edge(snk, snkDist)); } return dijkstra(src, snk); } int main(void) { in = fopen("block.in", "rt"); out = fopen("block.out", "wt"); fscanf(in, "%d", &n); for (int i = 0; i < n; i++) { fscanf(in, "%lf %lf %lf %lf", &a[i][0].x, &a[i][0].y, &a[i][1].x, &a[i][1].y); } fprintf(out, "%.2f\n", solve()); return 0; }