/** Solution for Season 6 Round 4 Problem 4 Senior Author: Anton Chernev */ #include #include #include #include #include using namespace std; const int MAX_N = 500 + 2; const double epsilon = 0.0000001; const double inf = 1001; struct Point { double x, y; Point(double _x, double _y) { x = _x; y = _y; } Point() {} Point operator + (Point A) { return Point(x + A.x, y + A.y); } Point operator - (Point A) { return Point(x - A.x, y - A.y); } Point operator * (double lambda) /// multiply a vector by a scalar { return Point(x * lambda, y * lambda); } double operator ^ (Point A) /// cross/vector product { return x * A.y - A.x * y; } }; struct Segment { Point A, B; Segment(Point _A, Point _B) { A = _A; B = _B; } Segment() {} }; struct Edge { int vertex; double weight; Edge(int _vertex, double _weight) { vertex = _vertex; weight = _weight; } Edge() {} bool operator < (const Edge &el) const { return el.weight < weight; } }; int N; int start, finish; Segment segments[MAX_N]; double adjacency[MAX_N][MAX_N]; priority_queue Queue; double minDistance[MAX_N]; void read() { scanf("%d", &N); start = N; finish = N + 1; for(int i = 0; i < N; ++i) { scanf("%lf%lf", &segments[i].A.x, &segments[i].A.y); scanf("%lf%lf", &segments[i].B.x, &segments[i].B.y); } segments[start] = Segment(Point(0, 0), Point(1000, 0)); segments[finish] = Segment(Point(0, 1000), Point(1000, 1000)); } inline double findDistance(Point A, Point B) { return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); } inline double orientedArea(Point A, Point B, Point C) { return (B - A) ^ (C - A); } inline double dotProduct(Point A, Point B) { return A.x * B.x + A.y * B.y; } bool checkIntersection(Segment segment1, Segment segment2) { if(orientedArea(segment1.A, segment1.B, segment2.A) * orientedArea(segment1.A, segment1.B, segment2.B) > 0) return false; if(orientedArea(segment2.A, segment2.B, segment1.A) * orientedArea(segment2.A, segment2.B, segment1.B) > 0) return false; return true; } double pointToSegmentDistance(Point A, Segment S) { if(dotProduct((S.B - S.A), (A - S.A)) >= 0 && dotProduct((S.A - S.B), (A - S.B)) >=0) return fabs((S.B - S.A) ^ (A - S.A)) / findDistance(S.A, S.B); return min(findDistance(A, S.A), findDistance(A, S.B)); } double segmentToSegmentDistance(Segment segment1, Segment segment2) { if(checkIntersection(segment1, segment2)) return 0.; Point M1, M2; double left, right, middle1, middle2; double distance1, distance2; left = 0.; right = 1.; while(right - left >= epsilon) { middle1 = left + (right - left) / 3.; middle2 = left + (right - left) * 2. / 3.; M1 = segment2.A + (segment2.B - segment2.A) * middle1; M2 = segment2.A + (segment2.B - segment2.A) * middle2; distance1 = pointToSegmentDistance(M1, segment1); distance2 = pointToSegmentDistance(M2, segment1); if(distance1 < distance2) right = middle2; else left = middle1; } return min(distance1, distance2); } void buildGraph() { for(int i = 0; i < N + 2; ++i) for(int j = 0; j < N + 2; ++j) if(i != j) adjacency[i][j] = adjacency[j][i] = segmentToSegmentDistance(segments[i], segments[j]); } double Dijkstra() { Edge el, el1; for(int i = 0; i < N + 2; ++i) minDistance[i] = inf; minDistance[start] = 0; Queue.push(Edge(start, 0)); while(!Queue.empty()) { el = Queue.top(); Queue.pop(); if(fabs(el.weight - minDistance[el.vertex]) < epsilon) for(int i = 0; i < N + 2; ++i) if(el.vertex != i && el.weight + adjacency[el.vertex][i] < minDistance[i]) { minDistance[i] = el.weight + adjacency[el.vertex][i]; Queue.push(Edge(i, minDistance[i])); } } return minDistance[finish]; } int main() { read(); buildGraph(); printf("%.2lf\n", Dijkstra()); }