Problem:
Problem B:
Electrophoretic
Scientist Frank, majoring in electrochemistry, has developed line-shaped strange electrodes called
F-electrodes
.
During being activated, each F-electrode causes a special potential on and between the two lines touching the
F-electrode’s endpoints at a right angle. Then electrically-charged particles located inside the potential area get
to move in the direction parallel to the potential boundary (i.e. perpendicular to the F-electrode), either toward or
against F-electrode. The moving direction can be easily controlled between the two possibles; it is also possible
to get particles to pass through F-electrodes. In addition, unlike ordinary electrodes, F-electrodes can affect
particles even infinitely far away, as long as those particles are located inside the potential area. On the other
hand, two different F-electrodes cannot be activated at a time, since their potentials conflict strongly.
We can move particles on our will by controlling F-electrodes. However, in some cases, we cannot lead them to
the desired positions due to the potential areas being limited. To evaluate usefulness of F-electrodes from some
aspect, Frank has asked you the following task: to write a program that finds the shortest distances from the
particles’ initial positions to their destinations with the given sets of F-electrodes.
Input
The input consists of multiple test cases. The first line of each case contains
N
(1 ≤
N
≤ 100) which represents
the number of F-electrodes. The second line contains four integers
x
s
,
y
s
,
x
t
and
y
t
, where (
x
s
,
y
s
) and (
x
t
,
y
t
)
indicate the particle’s initial position and destination. Then the description of
N
F-electrodes follow. Each line
contains four integers
Fx
s
,
Fy
s
,
Fx
t
and
Fy
t
, where (
Fx
s
,
Fy
s
) and (
Fx
t
,
Fy
t
) indicate the two endpoints of an
F-electrode. All coordinate values range from 0 to 100 inclusive.
The input is terminated by a case with
N
= 0.
Output
Your program must output the case number followed by the shortest distance between the initial position to
the destination. Output “Impossible” (without quotes) as the distance if it is impossible to lead the elementary
particle to the destination. Your answers must be printed with five digits after the decimal point. No absolute
error in your answers may exceed 10
-5
.
Sample Input
2
2 1 2 2
0 0 1 0
0 1 0 2
0
Output for the Sample Input
Case 1: 3.00000

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;

const int N = 205;
const int MAXN = 100005;
const LD eps = 1e-9;

inline int sgn(LD x) {
    return x > eps? 1 : x < -eps? -1 : 0;
}

struct Point {
    LD x, y;
    Point() {}
    Point(LD _x, LD _y): x(_x), y(_y) {}
    inline void input() {
        LL _x, _y;
        scanf("%lld %lld", &_x, &_y);
        x = _x; y = _y;
    }
    Point operator + (const Point &rhs) const {
        return Point(x + rhs.x, y + rhs.y);
    }
    Point operator - (const Point &rhs) const {
        return Point(x - rhs.x, y - rhs.y);
    }
    Point operator * (const LD &rhs) const {
        return Point(x * rhs, y * rhs);
    }
    Point operator / (const LD &rhs) const {
        return Point(x / rhs, y / rhs);
    }
    LD operator * (const Point &rhs) const {
        return x * rhs.x + y * rhs.y;
    }
    LD operator ^ (const Point &rhs) const {
        return x * rhs.y - y * rhs.x;
    }
    LD len2() {
        return x * x + y * y;
    }
    LD len() {
        return sqrt(len2());
    }
    Point rotateleft90() {
        return Point(-y, x);
    }
    bool operator < (const Point &rhs) const {
        return sgn(x - rhs.x)? (x < rhs.x) : (y < rhs.y);
    }
} cp[MAXN];

inline int side(Point u, Point v, Point p) {
    return sgn((v - u) ^ (p - u));
}

inline Point LineInter(Point u1, Point v1, Point u2, Point v2) {
    LD a1 = (v2 - u2) ^ (u1 - u2), a2 = (v2 - u2) ^ (v1 - u2);
    return (u1 * a2 - v1 * a1) / (a2 - a1);
}

struct Line {
    Point u, v;
    Line() {}
    Line(Point _u, Point _v): u(_u), v(_v) {}
} cl[MAXN];

int n, m, k;
vector<int> vec[MAXN];
vector<int> g[MAXN];

LD dis[MAXN];
bool vis[MAXN];
priority_queue< pair<LD, int> > pq;

void Dijkstra() {
    for (int i = 1; i <= k; ++i) {
        dis[i] = 1e18;
        vis[i] = 0;
    }
    dis[1] = 0;
    pq.push(make_pair(0, 1));
    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto v : g[u]) {
            LD w = (cp[v] - cp[u]).len();
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pq.push(make_pair(-dis[v], v));
            }
        }
    }
}

void solve() {
    for (int i = 1; i <= m; ++i) {
        vec[i].clear();
    }
    for (int i = 1; i <= k; ++i) {
        g[i].clear();
    }
    m = k = 0;

    cp[++k].input();
    cp[++k].input();
    bool direct = 0;
    for (int i = 1; i <= n; ++i) {
        Point a, b;
        a.input();
        b.input();
        Point dir = (b - a).rotateleft90();
        cl[++m] = Line(a, a + dir);
        cl[++m] = Line(b, b + dir);
        int tmp = m;
        for (int j = 1; j <= 2; ++j) {
            if (side(a, a + dir, cp[j]) * side(b, b + dir, cp[j]) <= 0) {
                cl[++m] = Line(cp[j], cp[j] + dir);
                vec[m].push_back(j);
            }
        }
        if (m - tmp == 2 && sgn((b - a) * (cp[2] - cp[1])) == 0) {
            direct = 1;
        }
    }
    if (direct) {
        printf("%.10Lf\n", (cp[2] - cp[1]).len());
        return;
    }

    for (int i = 1; i <= m; ++i) {
        for (int j = i + 1; j <= m; ++j) {
            if (sgn((cl[i].v - cl[i].u) ^ (cl[j].v - cl[j].u)) == 0) {
                continue;
            }
            Point inter = LineInter(cl[i].u, cl[i].v, cl[j].u, cl[j].v);
            cp[++k] = inter;
            vec[i].push_back(k);
            vec[j].push_back(k);
        }
    }
    for (int i = 1; i <= m; ++i) {
        sort(vec[i].begin(), vec[i].end(), [](int a, int b){ return cp[a] < cp[b];});
        for (int j = 0; j < (int)vec[i].size() - 1; ++j) {
            int u = vec[i][j], v = vec[i][j + 1];
            g[u].push_back(v);
            g[v].push_back(u);
        }
    }

    Dijkstra();
    if (dis[2] >= 1e17) {
        puts("Impossible");
    } else {
        printf("%.10Lf\n", dis[2]);
    }
}

int main() {
    for (int t = 1; ; ++t) {
        scanf("%d", &n);
        if (!n) break;
        printf("Case %d: ", t);
        solve();
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 13588
final_rank: 7

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <map>
#include <utility>
#include <queue>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectLP(const L& l, const P& p){
    return abs(cross(l[1]-p, l[0]-p)) < EPS;
}

bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}

pair<vector<vector<pair<int, double> > >, VP> arrangementEX(const vector<L> &l, const VP &p){
    vector<VP> cp(l.size());
    VP plist = p;
    for(int i=0; i<(int)l.size(); i++){
        for(int j=i+1; j<(int)l.size(); j++){
            if(!isParallel(l[i], l[j])){
                P cpij = crosspointLL(l[i], l[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        for(int j=0; j<(int)p.size(); j++){
            if(intersectLP(l[i], p[j])){
                cp[i].push_back(p[j]);
            }
        }
        cp[i].push_back(l[i][0]);
        cp[i].push_back(l[i][1]);
        plist.push_back(l[i][0]);
        plist.push_back(l[i][1]);
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());

    int n = plist.size();
    map<P, int> conv;
    for(int i=0; i<n; i++){
        conv[plist[i]] = i;
    }
    vector<vector<pair<int, double> > > adj(n);
    for(int i=0; i<(int)cp.size(); i++){
        for(int j=0; j<(int)cp[i].size()-1; j++){
            int jidx = conv[cp[i][j]];
            int jp1idx = conv[cp[i][j+1]];
            double dist = abs(cp[i][j] -cp[i][j+1]);
            adj[jidx].emplace_back(jp1idx, dist);
            adj[jp1idx].emplace_back(jidx, dist);
        }
    }
    for(int i=0; i<n; i++){
        sort(adj[i].begin(), adj[i].end());
        adj[i].erase(unique(adj[i].begin(), adj[i].end()), adj[i].end());
    }
    return make_pair(adj, plist);
}

int main(){
    int dn=1;
    while(1){
        int n;
        cin >> n;
        if(n == 0) break;

        VP sg(2);
        for(int i=0; i<2; i++){
            double x,y;
            cin >> x >> y;
            sg[i] = P(x, y);
        }
        vector<L> line(2*n);
        for(int i=0; i<n; i++){
            VP p(2);
            for(int j=0; j<2; j++){
                double x,y;
                cin >> x >> y;
                p[j] = P(x, y);
            }
            P ort = (p[1] -p[0]) *P(0, 1);
            line[2*i +0] = L(p[0], p[0]-ort);
            line[2*i +1] = L(p[1], p[1]+ort);
        }
        for(int i=0; i<n; i++){
            for(int j=0; j<2; j++){
                if(ccw(line[2*i +0][0], line[2*i +0][1], sg[j]) != -1 &&
                   ccw(line[2*i +1][0], line[2*i +1][1], sg[j]) != -1){
                    line.emplace_back(sg[j], sg[j] +line[2*i +0][1] -line[2*i +0][0]);
                }
            }  
        }

        pair<vector<vector<pair<int, double> > >, VP> ret = arrangementEX(line, sg);
        vector<vector<pair<int, double> > > &adj = ret.first;
        VP &plist = ret.second;
        int sidx = lower_bound(plist.begin(), plist.end(), sg[0]) -plist.begin();
        int gidx = lower_bound(plist.begin(), plist.end(), sg[1]) -plist.begin();        

        priority_queue<pair<double, int> > wait;
        wait.push(make_pair(0, sidx));
        vector<double> mincost(plist.size(), INF);
        mincost[sidx] = 0;
        while(!wait.empty()){
            double dist = -wait.top().first;
            int pos = wait.top().second;
            wait.pop();
            if(dist > mincost[pos] +EPS) continue;
            if(pos == gidx) break;
            for(pair<int, double> &next: adj[pos]){
                double ndist = dist +next.second;
                double npos = next.first;
                if(ndist +EPS < mincost[npos]){
                    wait.push(make_pair(-ndist, npos));
                    mincost[npos] = ndist;
                }
            }
        }

        cout << fixed << setprecision(5);
        cout << "Case " << dn++ << ": ";
        if(mincost[gidx] == INF){
            cout << "Impossible" << endl;
        }else{
            cout << mincost[gidx] << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 11764
final_rank: 6

code_snippet: #include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
using namespace std;

const int N = 300 + 10;
const int V = N * N;
const int M = V * 10;
const double INF = 1e10;
const double EPS = 1e-8;

int sign(long double x)
{
	return x < -EPS ? -1 : x > EPS;
}

struct Edge
{
	double w;
	int t;
	Edge *n;
};

Edge edges[M], *totEdge, *firstEdge[V];

struct Point
{
	long double x, y;
	Point() {}
	Point(long double x, long double y) : x(x), y(y) {
	}
	Point operator + (const Point &that) const {
		return Point(x + that.x, y + that.y);
	}
	Point operator - (const Point &that) const {
		return Point(x - that.x, y - that.y);
	}
	Point operator * (const long double &that) const {
		return Point(x * that, y * that);
	}
	Point operator / (const long double &that) const {
		return Point(x / that, y / that);
	}
	void read() {
		cin >> x >> y;
	}
	Point rot90() {
		return Point(y, -x);
	}
	int operator < (const Point &that) const {
		int d = sign(x - that.x);
		if (d) return d < 0;
		return sign(y - that.y) < 0;
	}
	long double det(const Point &that) const {
		return x * that.y - that.x * y;
	}
	long double distTo(const Point &that) const {
		return hypot(x - that.x, y - that.y);
	}
	void write() {
		cout << "(" << x << "," << y << ") ";
	}
};

#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define crossOp(p1,p2,p3) sign(cross(p1,p2,p3))

int n, tot;
vector<pair<Point, Point> > lines;
vector<Point> pointList;
vector<int> pointOnLine[N];
map<Point, int> points;
Point s, t;
Point a[N][2];

int insert(Point u)
{
	if (points.count(u) == 0) {
		pointList.push_back(u);
		points[u] = tot ++;
	}
	return points[u];
}

Point isSS(Point p1, Point p2, Point q1, Point q2)
{
	long double a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
	return (p1 * a2 + p2 * a1) / (a1 + a2);
}

int cmp(const int &a, const int &b)
{
	return pointList[a] < pointList[b];
}

void addEdge(int s, int t, long double w)
{
	Edge *e = totEdge ++;
	e->w = w; e->t = t; e->n = firstEdge[s]; firstEdge[s] = e;
}

long double dij(int s, int t)
{
	priority_queue< pair<double, int> > que;
	int in[V];
	double dis[V];
	for(int i = 0; i < tot; ++ i) {
		dis[i] = INF;
		in[i] = false;
	}
	dis[s] = 0;
	que.push(make_pair(0, s));

	for( ; que.size(); ) {
		int u = que.top().second;
		que.pop();
		if (in[u]) continue;
		in[u] = true;
		if (u == t) return dis[t];
		for(Edge *e = firstEdge[u]; e; e = e->n) {
			int v = e->t;
			if (dis[v] > dis[u] + e->w) {
				dis[v] = dis[u] + e->w;
				que.push(make_pair(-dis[v], v));
			}
		}
	}
	return INF;
}

void solve()
{
	lines.clear();
	s.read(); t.read();
	for(int i = 0; i < n; ++ i) {
		a[i][0].read();
		a[i][1].read();
		Point vec = (a[i][1] - a[i][0]).rot90();
		Point s1 = a[i][0], t1 = s1 + vec;
		Point s2 = a[i][1], t2 = s2 + vec;
		lines.push_back(make_pair(s1, t1));
		lines.push_back(make_pair(s2, t2));
		if (crossOp(s1, t1, s) * crossOp(s2, t2, s) <= 0) {
			lines.push_back(make_pair(s, s + vec));
		}
		if (crossOp(s1, t1, t) * crossOp(s2, t2, t) <= 0) {
			lines.push_back(make_pair(t, t + vec));
		}
	}
	
	pointList.clear();
	tot = 0;
	points.clear();
	insert(s);
	insert(t);

	for(int i = 0; i < lines.size(); ++ i) {
		pointOnLine[i].clear();
	}
	for(int i = 0; i < lines.size(); ++ i) {
		if (crossOp(lines[i].first, lines[i].second, s) == 0) {
			pointOnLine[i].push_back(insert(s));
		}
		if (crossOp(lines[i].first, lines[i].second, t) == 0) {
			pointOnLine[i].push_back(insert(t));
		}
		for(int j = i + 1; j < lines.size(); ++ j) {
			if (sign((lines[i].second - lines[i].first).det(lines[j].second - lines[j].first)) == 0) 
				continue;
			Point p = isSS(lines[i].first, lines[i].second, lines[j].first, lines[j].second);
			int id = insert(p);
			pointOnLine[i].push_back(id);
			pointOnLine[j].push_back(id);
		}
	}

	totEdge = edges;
	for(int i = 0; i < tot; ++ i) {
		firstEdge[i] = 0;
	}
	for(int i = 0; i < lines.size(); ++ i) {
		sort(pointOnLine[i].begin(), pointOnLine[i].end(), cmp);
		pointOnLine[i].resize(unique(pointOnLine[i].begin(), pointOnLine[i].end()) - pointOnLine[i].begin());
		for(int j = 1; j < pointOnLine[i].size(); ++ j) {
			int u = pointOnLine[i][j - 1], v = pointOnLine[i][j];
			addEdge(u, v, pointList[u].distTo(pointList[v]));
			addEdge(v, u, pointList[u].distTo(pointList[v]));
		}
	}

	double ret = dij(points[s], points[t]);
	if (ret >= INF) cout << "Impossible" << endl;
	else {
		printf("%.12f\n", (double)ret);
	}
}

int main()
{
	int test = 0;
	for( ; cin >> n && n; ) {
		printf("Case %d: ", ++ test);
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 8548
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

using namespace std;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
// verify : not yet.
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

// 直線ABに対する点Cの位置
int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 注意: 端点で交わったり直線が重なったりする場合も交差していると判定する

// 二直線の平行判定
// verify : AOJ0021
bool paralell(L l, L m){return sign(cross(vec(l), vec(m))) == 0;}

// 二直線の同一判定
bool equalLL(L l, L m){return paralell(l, m) && sign(cross(vec(l), m[0] - l[0])) == 0;}

// 直線と点の交差判定
// 直線lとl[0]からpへの直線が平行
bool iLP(L l, P p) {return sign(cross(vec(l), p - l[0])) == 0;}

// 線分と点の交差判定(端点の処理に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と線分の交差判定(線分が重なっている時に注意)
// 直線lについて、線分sの端点が異なる側にある
bool iLS(L l, L s) {return sign(cross(vec(l), s[0] - l[0]) * cross(vec(l), s[1] - l[0])) <= 0;}

// 二つの線分の交差判定(線分が重なっている時や端点の処理に注意)
bool iSS(L s, L t) {
    auto ok = [](L a, L b){return ccw(a[0],a[1],b[0]) * ccw(a[0],a[1],b[1]) <= 0;};
    return ok(s,t) && ok(t,s);
}


// 点pから直線lに対する射影
P proj(L l, P p){
    double t = dot(p - l[0], vec(l)) / norm(vec(l));
    return l[0] + t * vec(l);
}

// 点pの直線lに関する反射
P refl(L l, P p){return 2.0 * proj(l, p) - p;}

// 直線と点の距離
// Verified: AOJ 2201
double dLP(L l, P p){return abs(cross(vec(l), p - l[0])) / abs(vec(l));}

// 線分と点の距離
double dSP(L s, P p){
    if(sign(dot(vec(s), p - s[0])) <= 0) return abs(p - s[0]);
    if(sign(dot(-vec(s), p - s[1])) <= 0) return abs(p - s[1]);
    return dLP(s, p);
}

// 直線と直線の距離
double dLL(L l, L m){
    // 平行でないときは0, 平行のときは垂線の長さ
    return paralell(l, m) ? dLP(l, m[0]) : 0;
}

// 直線と線分の距離
double dLS(L l, L s){return iLS(l,s) ? 0.0 : min(dLP(l, s[0]), dLP(l, s[1]));}

// 線分と線分の距離
// Verified: AOJ 1157
double dSS(L s, L t){return iSS(s,t) ? 0.0 : min({dSP(s, t[0]), dSP(s, t[1]), dSP(t, s[0]), dSP(t, s[1])});}

// 直線と直線の交点
// Verified: AOJ2579
P pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return m[0]; // 二直線が重なっている
    if(sign(A) == 0) assert(false); // 直線が交わらない
    return m[0] + vec(m) * B / A;
}
typedef vector<P> Pol; // 反時計回りを仮定

// 点が多角形のどこにあるのか判定する
// verify : AOJ0012
int contains(const Pol& A, P p){
    // 点pから半直線をひき、辺と交差する回数を数える
    int in = 0;
    int n = A.size();
    for(int i = 0; i < n; i++){
        P a = A[i] - p;
        P b = A[(i + 1) % n] - p;
        if(a.imag() > b.imag()) swap(a, b);
        // aからbの直線がy=0と交わり、その交点は原点の右側である
        in ^= a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0;

        if(sign(cross(a, b)) == 0 && sign(dot(a, b)) <= 0) return ON;
    }
    return in ? IN : OUT;
}

// 多角形の面積
// verify : AOJ0079 AOJ1100
double area(const Pol& A) {
    double res = 0;
    int n = A.size();
    for(int i = 0; i < n; i++){
        res += cross(A[i], A[(i + 1) % n]);
    }
    return abs(res) / 2.0;
}
// 凸包
Pol convex_hull(vector<P> ps) {
    int n = ps.size(), k = 0;
    sort(ps.begin(), ps.end(),[](const P&a, const P&b){
            return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
            });

    vector<P> ch(2*n);
    for (int i = 0; i < n; ch[k++] = ps[i++]){ // lower-hull
        while (k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
    }
    for (int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--]){ // upper-hull
        while (k >= t && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
    }
    ch.resize(k-1);
    return ch;
}

bool is_convex(const Pol& A){
    int n = A.size();
    for(int i = 0; i < n; i++){
        if(ccw(A[i], A[(i + 1) % n], A[(i + 2) % n]) > 0) return false;
    }
    return true;
}

// 凸多角形の直線による切断。直線の左側だけ残す
// verify : aoj1283
Pol convex_cut(const Pol& A, L l){
    int n = A.size();
    Pol B;
    for(int i = 0; i < n; i++){
        P a = A[i], b = A[(i + 1) % n];
        if(ccw(l[0], l[1], a) != -1) B.push_back(a); //Aが直線lの右側でない
        if(ccw(l[0], l[1], a) * ccw(l[0], l[1], b) < 0)
            B.push_back(pLL(l, {a, b}));
    }
    return B;
}
// 垂直二等分線
// verify: maximamcup2013 D
L bisector(P a, P b){
    P mid = (a + b) / 2.0;
    P vec = (mid - a) * P(0.0, 1.0);
    return {mid, mid + vec};
}
// 点集合psのうちs番目のボロノイ領域
// verify: maximamcup2013 D
Pol voronoi_cell(Pol A, const vector<P>& ps, int s){
    for(int i = 0; i < ps.size(); i++){
        if(i != s) A = convex_cut(A, bisector(ps[s], ps[i]));
    }
    return A;
}
struct C{P p;double r;};

// 円と点の内外判定
// Verified: AOJ2181, AOJ2579
int contains(C c, P p){
    double d = abs(c.p - p);
    if(sign(d - c.r) > 0) return OUT;
    if(sign(d - c.r) == 0) return ON;
    return IN;
}

// 円と線分の交差判定(境界を含む)
// 接するときに注意!!
// Verified: AOJ0129, AOJ2506, AOJ2579
bool iCS(C c, L l){
    int c1 = contains(c, l[0]);
    int c2 = contains(c, l[1]);
    if(c1 > c2) swap(c1, c2);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(c1 == OUT && c2 == IN) return true;
    if(c1 == IN  && c2 == IN) return false;
    if(c1 == ON) return true; // (接するとき) 
    double d = dSP(l, c.p);
    if(sign(d - c.r) < 0) return true;
    if(sign(d - c.r) == 0) return true; // (接するとき)
    if(sign(d - c.r) > 0) return false;
    assert(false);
}

// 二つの円の交差判定(接する時を含む)
// verified: AOJ 2181
bool iCC(C c, C d){
    // 円の中心同士の距離が、半径の和以下であり、半径の差以上である
    double e = abs(d.p - c.p);
    return sign(e - (c.r + d.r)) <= 0 && sign(e - abs(c.r - d.r)) >= 0;
}

// 円cに対して円dがどの位置にあるか(IN:内側, ON: 交差, OUT: それ以外)
// Verified: AOJ 2181
int contains(C c, C d) {
    double e = abs(c.p - d.p);
    if(sign(c.r - d.r) > 0 && sign(c.r - (d.r + e)) > 0) return IN;
    if(iCC(c, d)) return ON;
    return OUT;
}

// 円と直線の交点
// verify : AOJ2045
vector<P> pCL(C c, L l) {
    vector<P> res;
    P center = proj(l, c.p);
    double d = abs(center - c.p);
    double tt = c.r * c.r - d * d;
    if(tt < 0 && tt > -EPS) tt = 0;
    if(tt < 0) return res;
    double t = sqrt(tt);
    P vect = vec(l);
    vect /= abs(vect);
    res.push_back(center - vect * t);
    if (t > EPS) {
        res.push_back(center + vect * t);
    }
    return res;
}

// 円と線分の交点
vector<P> pCS(C c, L s) {
    vector<P> ret;
    vector<P> nret = pCL(c, s);
    for (int i = 0; i < nret.size(); i++) {
        if (iSP(s, nret[i])) ret.push_back(nret[i]);
    }
    return ret;
}

// 円と円の交点
// verify : AOJ1183
vector<P> pCC(C a, C b){
    vector<P> res;

    double l = abs(b.p - a.p);

    if(sign(l) == 0 && sign(a.r - b.r) == 0) assert(false); // 解が無限に存在する
    if(sign(l - abs(a.r - b.r)) < 0 || sign(l - (a.r + b.r)) > 0) return res; // 解が存在しない

    double th1 = arg(b.p - a.p);
    if(sign(l - abs(a.r - b.r)) == 0 || sign(l - (a.r + b.r)) == 0){
        res.push_back(a.p + polar(a.r, th1));
    }else {
        double th2 = acos( (a.r * a.r - b.r * b.r + l * l) / (2 * a.r * l) );
        res.push_back(a.p + polar(a.r, th1 - th2));
        res.push_back(a.p + polar(a.r, th1 + th2));
    }
    return res;
}

// 2点を通る半径rの円の中心
// verify : AOJ1132
vector<P> touching_circle2(P a, P b, double r){
    vector<P> res;

    double d = abs(b - a);
    if(d > 2 * r) return res;

    P mid = 0.5 * (a + b);
    P dir = polar(sqrt(r * r - d * d / 4), arg(b - a) + M_PI / 2);
    res.push_back(mid + dir);
    res.push_back(mid - dir);
    return res;
}

// 3点を通る円
C touching_circle3(P a, P b, P c){
    // ２つの垂直二等分線の交点が円の中心
    P mid_ab = (a + b) / 2.0;
    L bis_ab = {mid_ab, (mid_ab - a) * P(0.0, 1.0)};
    P mid_bc = (b + c) / 2.0;
    L bis_bc = {mid_bc, (mid_bc - b) * P(0.0, 1.0)};

    assert(!paralell(bis_ab, bis_bc)); 

    P center = pLL(bis_ab, bis_bc);
    return {center, abs(a - center)};
}

// 円と円の共通部分の面積を求める．
// ref: nya3j
double cc_area(C c1, C c2) {
    double d = abs(c1.p - c2.p);
    if (c1.r + c2.r < d + EPS) {
        return 0.0;
    } else if (d < abs(c1.r - c2.r) + EPS) {
        double r = min(c1.r, c2.r); // 元は c1.r >? c2.r だった．
        return r * r * M_PI;
    } else {
        double rc = (d*d + c1.r*c1.r - c2.r*c2.r) / (2*d);
        double theta = acos(rc / c1.r);
        double phi = acos((d - rc) / c2.r);
        return c1.r*c1.r*theta + c2.r*c2.r*phi - d*c1.r*sin(theta);
    }
}

// 円の接線 (中心から偏角thの点で接する接線)
// verified: AOJ 2201
L circle_tangent(const C& c, double th){
    P p0 = c.p + polar(c.r, th);
    P p1 = p0 + polar(1.0, th + M_PI / 2);
    return {p0, p1};
}

// 二つの円の共通接線 (cの中心から接点へのベクトルの偏角を返す)
// verified: AOJ 2201
// 参考: http://geom.web.fc2.com/geometry/circle-circle-tangent.html
vector<double> common_tangents(const C& c, const C& d){
    vector<double> res;
    P v = d.p - c.p;
    double l = abs(v); // 二円の中心間の距離
    double a = arg(v); // 二円の中心間の偏角
    if(sign(l - abs(c.r - d.r)) > 0){
        // 交わる or 外接 or 離れている
        // 二つの外側接線
        double a1 = acos((c.r - d.r) / l);
        res.push_back(a + a1);
        res.push_back(a - a1);
        if(sign(l - (c.r + d.r)) > 0){
            // 離れている
            // 二つの内側接線
            double a2 = acos((c.r + d.r) / l);
            res.push_back(a + a2);
            res.push_back(a - a2);
        }
    }
    if((sign(l - abs(c.r - d.r)) == 0 || sign(l - (c.r + d.r)) == 0) && sign(l) != 0){
        // 内接 or 外接
        // 一つの接線
        res.push_back(a);
    }
    return res;
}

// 1点を通る円の接線( pがcの外側にあることが前提条件 )
// verified : AOJ 2579
vector<L> tangents_through_point(const C& c, const P& p){
    vector<L> tangents;
    double d = abs(c.p - p);
    // d ^ 2 == r ^ 2 + e ^ 2
    double e = sqrt(d * d - c.r * c.r); // 点pと円の接点の距離
    // d * sin(th) = r
    double th = asin(c.r / d);
    P q1 = p + (c.p - p) * polar(1.0, +th) * e / d;
    P q2 = p + (c.p - p) * polar(1.0, -th) * e / d;
    tangents.push_back({p, q1});
    tangents.push_back({p, q2});
    return tangents;
}
// 三角形の内心
// verify : aoj 1301
P incenter(P p1, P p2, P p3){
    double a = abs(p2 - p3);
    double b = abs(p3 - p1);
    double c = abs(p1 - p2);
    return (a * p1 + b * p2 + c * p3) / (a + b + c);
}


P input(){
    double x, y;
    cin >> x >> y;
    return {x, y};
}
struct S{
    int cur, prev;
    double cost;
    bool operator < (const S& s) const {
        if(cost != s.cost) return cost > s.cost;
        return make_pair(cur, prev) < make_pair(s.cur, s.prev);
    }
    void print(){
        printf("%d -> %d : %f\n", prev, cur, cost);
    }
};
int main(){
    int N;
    int casenum = 0;
    while(cin >> N && N){
        P sp = input();
        P gp = input();
        vector<L> elec(N);
        REP(i, N) {
            P pa = input();
            P pb = input();
            elec[i] = {pa, pb};
        }

        vector<L> route;
        REP(i, N) {
            P v = vec(elec[i]) * P(0, 1);
            L l = {sp, sp + v};
            if(iLS(l, elec[i])) {
                route.push_back(l);
            }
        }
        priority_queue<S> que;
        int M = route.size();
        REP(i, N) {
            P v = vec(elec[i]) * P(0, 1);
            route.push_back({elec[i][0], elec[i][0] + v});
            route.push_back({elec[i][1], elec[i][1] + v});
        }
        REP(i, N) {
            P v = vec(elec[i]) * P(0, 1);
            L l = {gp, gp + v};
            if(iLS(l, elec[i])) {
                route.push_back(l);
            }
        }
        // REP(i, route.size()){
        //     cout << "route " << i << " " << route[i][0] << " " << route[i][1] << endl;
        // }
        bool adj[500][500] = {};
        P cpp[500][500] = {};
        REP(i, route.size()) REP(j, route.size()) {
            if(!paralell(route[i], route[j])){
                cpp[i][j] = pLL(route[i], route[j]);
                adj[i][j] = true;
            }
        }
        double res = DBL_MAX;
        double mind[500][500] = {};
        REP(i, route.size()) REP(j, route.size()) {
            mind[i][j] = DBL_MAX;
        }

        // [0, M) [M, M + 2 * N) [M + 2 * N, route.size())
        for(int i = 0; i < M; i++) {
            for(int j = M; j < route.size(); j++){
                if(adj[i][j]) {
                    // mind[j][i] = abs(sp - cpp[j][i]);
                    que.push({j, i, abs(sp - cpp[j][i])});
                }
                if(equalLL(route[i], route[j])){
                    assert(paralell(route[i], route[j]));
                    cpp[i][j] = cpp[j][i] = sp;
                    // mind[j][i] = 0;
                    que.push({j, i, 0.0});
                }
            }
        }

        while(!que.empty()){
            S s = que.top(); que.pop();
            // s.print();
            if(s.cur >= M + 2 * N) {
                res = min(res, s.cost + abs(gp - cpp[s.cur][s.prev]));
                continue;
            }
            if(mind[s.cur][s.prev] < s.cost) {
                continue;
            }
            for(int i = M; i < route.size(); i++) if(adj[i][s.cur]) {
                double ncost = s.cost + abs(cpp[s.cur][s.prev] - cpp[i][s.cur]);
                if(ncost < mind[i][s.cur]){
                    mind[i][s.cur] = ncost;
                    que.push({i, s.cur, ncost});
                }
            }
        }
        if(res < DBL_MAX) {
            printf("Case %d: %.5f\n", ++casenum, res);
        }else {
            printf("Case %d: Impossible\n", ++casenum);
        }

    }
    return 0;
}
accuracy: 1
time_ms: 1170
memory_kb: 23388
final_rank: 9

code_snippet: #include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
#include<cassert>
#include<iomanip>
#include<complex>
#include<queue>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define EPS (1e-8)
#define all(n) (n).begin(),(n).end()
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
#define equals(a,b) (fabs((a)-(b)) < EPS)

using namespace std;

//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

class Point
{
  public:
  double x,y;

  Point(double x = -inf,double y = -inf): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}

  bool operator < (const Point& p) const
  {
    return !equals(x,p.x)?x<p.x:y<p.y;
  }

  bool operator == (const Point& p)const
  {
    return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
  }

};

struct Segment
{
  Point p1,p2;
  Segment(Point p1 = Point(-inf,-inf),Point p2 = Point(-inf,-inf)):p1(p1),p2(p2){}
  bool operator == (const Segment& p)const
  {
    return p.p1 == p1 && p.p2 == p2;
  }
};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a)
{
  os << "(" << a.x << "," << a.y << ")";
}

ostream& operator << (ostream& os,const Segment& a)
{
  os << "( " << a.p1 << " , " << a.p2 << " )";
}

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad テ」ツ?ッティツァツ津・ツコツヲテ」ツつ津」ツδゥテ」ツつクテ」ツつ「テ」ツδウテ」ツ?ァテヲツ個?」ツ?淌」ツ?崚」ツつ凝」ツ?禿」ツ?ィ
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// テ・ツコツヲテ」ツつ津」ツδゥテ」ツつクテ」ツつ「テ」ツδウテ」ツ?ォテ・ツ、ツ嘉ヲツ渉?
double toRad(double agl){ return agl*M_PI/180.0; }

int ccw(Point p0,Point p1,Point p2)
{
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}

Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}

double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}
Point crosspoint(Line l, Line m) {
  double A = cross(l.p2 - l.p1, m.p2 - m.p1);
  double B = cross(l.p2 - l.p1, l.p2 - m.p1);
  if (abs(A) < EPS && abs(B) < EPS) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}



// -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-|

struct SP
{
  Segment seg;
  int type;// type 0 -> Point, type 1 -> Segment;
  SP(Segment seg = Segment(),int type=inf):seg(seg),type(type){}
};

struct Edge
{
  int from,to;
  double cost;
  Edge(int from=inf,int to=inf,double cost=inf):from(from),to(to),cost(cost){}
  bool operator < (const Edge& a)const
  {
    return cost < a.cost;
  }
};

typedef vector<Edge> vE;
typedef vector<vE> vvE;

int N;
vector<SP> vec;


vector<vector<Edge> > segmentArrangementVer1(vector<Segment> vs,vector<Point> &ps)
{

  rep(i,vs.size())
    REP(j,i+1,vs.size())
      if(intersectSS(vs[i],vs[j]))
        ps.push_back(Point(crosspoint(vs[i],vs[j])));

  //
  ps.push_back(vec[0].seg.p1);
  ps.push_back(vec[1].seg.p2);
  //

  sort(all(ps));  
  ps.erase(unique(all(ps)),ps.end());

  vector<vector<Edge> > ret(ps.size());

  for(int i=0;i<vs.size();i++)
    {
      vector<pair<double,int> > list;
      rep(j,ps.size())
	if(intersectSP(vs[i],ps[j]))
	  list.push_back(pair<double,int>(norm(vs[i].p1-ps[j]),j));

      sort(all(list));

      //for(int j=0;j<list.size()-1;++j) is not good -> テ」ツつサテ」ツつーテ」ツつ?
      for(int j=0;j+1<list.size();++j)
	{
	  int from = list[j].second, to = list[j+1].second;
	  double cost = abs(ps[from]-ps[to]);
	  ret[from].push_back(Edge(from,to,cost));
	  ret[to].push_back(Edge(to,from,cost));
	}
    }  
  return ret;
}

void toSegOnly(vector<Segment> &vs)
{
  rep(i,2)
    {
      REP(j,2,2+N)
	{
	  assert(vec[i].seg.p1 == vec[i].seg.p2);
	  Point prj = projection(vec[j].seg,vec[i].seg.p1);
	  if(intersectSP(vec[j].seg,prj))
	    {
	      if(vec[i].seg.p1 == prj)continue;
	      Point e = vec[i].seg.p1 - prj;
	      e = (e/abs(e))*1000;//100000テ」ツ?ィテ」ツ?凝」ツ?ォテ」ツ?凖」ツつ凝」ツ?ィティツェツ、テ・ツキツョテ」ツ?ァdeath
	      vs.push_back(Segment(vec[i].seg.p1-e,prj+e));
	    }
	}
    }

  REP(j,2,2+N)
    {
      Segment seg = Segment(vec[j].seg.p1 - vec[j].seg.p2,vec[j].seg.p2 - vec[j].seg.p2);
      Point rig = rotate(seg.p1,toRad(90.0));
      rig = (rig/abs(rig))*1000;
      vs.push_back(Segment(vec[j].seg.p1-rig,vec[j].seg.p1+rig));
      vs.push_back(Segment(vec[j].seg.p2-rig,vec[j].seg.p2+rig));
    }
}

//segment merge--------
bool merge_if_able(Segment &s, Segment t) {
  if (abs(cross(s.p2-s.p1, t.p2-t.p1)) > EPS) return false;
  if (ccw(s.p1, t.p1, s.p2) == +1 ||
      ccw(s.p1, t.p1, s.p2) == -1) return false; // not on the same line
  if (ccw(s.p1, s.p2, t.p1) == -2 ||
      ccw(t.p1, t.p2, s.p1) == -2) return false; // separated
  s = Segment(min(s.p1, t.p1), max(s.p2, t.p2));
  return true;
}
void merge_segments(vector<Segment>& segs) {
  for (int i = 0; i < segs.size(); ++i)
    if (segs[i].p2 < segs[i].p1)
      swap(segs[i].p2, segs[i].p1);
  for (int i = 0; i < segs.size(); ++i)
    for (int j = i+1; j < segs.size(); ++j)
      if (merge_if_able(segs[i], segs[j]))
        segs[j--] = segs.back(), segs.pop_back();
}
// -------------------

struct Pox
{
  int cur;
  double cost;
  Pox(int cur=inf,double cost=inf):cur(cur),cost(cost){}
  bool operator < (const Pox& a)const
  {
    return cost > a.cost;
  }
};

void dijkstra(vvE &G,int st,int ed)
{
  int n = G.size();
  double mincost[n];
  rep(i,n)mincost[i] = inf;
  mincost[st] = 0;
  priority_queue<Pox> Q;
  Q.push(Pox(st,0));

  while(!Q.empty())
    {
      Pox pox = Q.top(); Q.pop();

      if(pox.cur == ed)
	{
	  cout << setiosflags(ios::fixed) << setprecision(5) << pox.cost << endl;
	  return;
	}

      rep(i,G[pox.cur].size())
	{
	  int next = G[pox.cur][i].to;
	  double cost = G[pox.cur][i].cost;
	  if(!equals(mincost[next],pox.cost+cost) && mincost[next] > pox.cost + cost)
	    {
	      mincost[next] = pox.cost + cost;
	      Q.push(Pox(next,pox.cost+cost));
	    }
	}

    }
  cout << "Impossible" << endl;
}

void compute()
{
  vector<Segment> vs;
  toSegOnly(vs);

  merge_segments(vs);  

  vector<Point> ps;
  vvE G = segmentArrangementVer1(vs,ps);

  int st_index,ed_index;
  rep(i,ps.size())
    {
      if(ps[i] == vec[0].seg.p1)st_index = i;
      if(ps[i] == vec[1].seg.p1)ed_index = i;
    }

  dijkstra(G,st_index,ed_index);
   
}

int main()
{
  int CNT = 1;
  while(cin >> N,N)
    {
      vec.clear();
      vec.resize(N+2);
      double x,y;
      rep(i,2)
	{
	  cin >> x >> y;
	  vec[i].seg.p1 = vec[i].seg.p2 = Point(x,y);
	  vec[i].type = 0;
	}
      rep(i,N)
	cin >> vec[2+i].seg.p1.x >> vec[2+i].seg.p1.y >> vec[2+i].seg.p2.x >> vec[2+i].seg.p2.y;
      cout << "Case " << CNT++ << ": ";
      compute();
    }
  return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 4504
final_rank: 5

code_snippet: #include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
#include<cassert>
#include<iomanip>
#include<complex>
#include<queue>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define EPS (1e-8)
#define all(n) (n).begin(),(n).end()
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
#define equals(a,b) (fabs((a)-(b)) < EPS)

using namespace std;

//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

class Point
{
  public:
  double x,y;

  Point(double x = -inf,double y = -inf): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}

  bool operator < (const Point& p) const
  {
    return !equals(x,p.x)?x<p.x:y<p.y;
  }

  bool operator == (const Point& p)const
  {
    return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
  }

};

struct Segment
{
  Point p1,p2;
  Segment(Point p1 = Point(-inf,-inf),Point p2 = Point(-inf,-inf)):p1(p1),p2(p2){}
  bool operator == (const Segment& p)const
  {
    return p.p1 == p1 && p.p2 == p2;
  }
};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a)
{
  os << "(" << a.x << "," << a.y << ")";
}

ostream& operator << (ostream& os,const Segment& a)
{
  os << "( " << a.p1 << " , " << a.p2 << " )";
}

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// 度をラジアンに変換
double toRad(double agl){ return agl*M_PI/180.0; }

int ccw(Point p0,Point p1,Point p2)
{
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

bool intersectLL(Line l, Line m) {
  return abs(cross(l.p2-l.p1, m.p2-m.p1)) > EPS || // non-parallel
         abs(cross(l.p2-l.p1, m.p1-l.p1)) < EPS;   // same line
}
bool intersectLS(Line l, Line s) {
  return cross(l.p2-l.p1, s.p1-l.p1)*       // s[0] is left of l
         cross(l.p2-l.p1, s.p2-l.p1) < EPS; // s[1] is right of l
}
bool intersectLP(Line l,Point p) {
  return abs(cross(l.p2-p, l.p1-p)) < EPS;
}
bool intersectSS(Line s, Line t) {
  return ccw(s.p1,s.p2,t.p1)*ccw(s.p1,s.p2,t.p2) <= 0 &&
         ccw(t.p1,t.p2,s.p1)*ccw(t.p1,t.p2,s.p2) <= 0;
}
bool intersectSP(Line s, Point p) {
  return abs(s.p1-p)+abs(s.p2-p)-abs(s.p2-s.p1) < EPS; // triangle inequality
}

Point projection(Line l,Point p) {
  double t = dot(p-l.p1, l.p1-l.p2) / norm(l.p1-l.p2);
  return l.p1 + (l.p1-l.p2)*t;
}
Point reflection(Line l,Point p) {
  return p + (projection(l, p) - p) * 2;
}
double distanceLP(Line l, Point p) {
  return abs(p - projection(l, p));
}
double distanceLL(Line l, Line m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m.p1);
}

double distanceLS(Line l, Line s) {
  if (intersectLS(l, s)) return 0;
  return min(distanceLP(l, s.p1), distanceLP(l, s.p2));
}
double distanceSP(Line s, Point p) {
  Point r = projection(s, p);
  if (intersectSP(s, r)) return abs(r - p);
  return min(abs(s.p1 - p), abs(s.p2 - p));
}

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}
Point crosspoint(Line l, Line m) {
  double A = cross(l.p2 - l.p1, m.p2 - m.p1);
  double B = cross(l.p2 - l.p1, l.p2 - m.p1);
  if (abs(A) < EPS && abs(B) < EPS) return m.p1; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m.p1 +   (m.p2 - m.p1) * (B / A);
}



// -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-|

struct SP
{
  Segment seg;
  int type;// type 0 -> Point, type 1 -> Segment;
  SP(Segment seg = Segment(),int type=inf):seg(seg),type(type){}
};

struct Edge
{
  int from,to;
  double cost;
  Edge(int from=inf,int to=inf,double cost=inf):from(from),to(to),cost(cost){}
  bool operator < (const Edge& a)const
  {
    return cost < a.cost;
  }
};

typedef vector<Edge> vE;
typedef vector<vE> vvE;

int N;
vector<SP> vec;


vector<vector<Edge> > segmentArrangementVer1(vector<Segment> vs,vector<Point> &ps)
{

  rep(i,vs.size())
    REP(j,i+1,vs.size())
      if(intersectSS(vs[i],vs[j]))
        ps.push_back(Point(crosspoint(vs[i],vs[j])));

  //
  ps.push_back(vec[0].seg.p1);
  ps.push_back(vec[1].seg.p2);
  //

  sort(all(ps));  
  ps.erase(unique(all(ps)),ps.end());

  vector<vector<Edge> > ret(ps.size());

  for(int i=0;i<vs.size();i++)
    {
      vector<pair<double,int> > list;
      rep(j,ps.size())
	if(intersectSP(vs[i],ps[j]))
	  list.push_back(pair<double,int>(norm(vs[i].p1-ps[j]),j));

      sort(all(list));

      //for(int j=0;j<list.size()-1;++j) is not good
      for(int j=0;j+1<list.size();++j)
	{
	  int from = list[j].second, to = list[j+1].second;
	  double cost = abs(ps[from]-ps[to]);
	  ret[from].push_back(Edge(from,to,cost));
	  ret[to].push_back(Edge(to,from,cost));
	}
    }  
  return ret;
}

void toSegOnly(vector<Segment> &vs)
{
  rep(i,2)
    {
      REP(j,2,2+N)
	{
	  assert(vec[i].seg.p1 == vec[i].seg.p2);
	  Point prj = projection(vec[j].seg,vec[i].seg.p1);
	  //cout << i << "," << j << " : " << prj << endl;
	  if(intersectSP(vec[j].seg,prj))
	    {
	      if(vec[i].seg.p1 == prj)continue;
	      //cout << vec[i].seg.p1 << " intersect : " << i << " and " << j << " " << prj << endl; 
	      Point e = vec[i].seg.p1 - prj;
	      //cout << "fe : " << e << endl;
	      e = (e/abs(e))*1000;
	      //cout << "e : " << e << endl;
	      vs.push_back(Segment(vec[i].seg.p1-e,prj+e));
	    }
	}
    }
  /*
  cout << "VS =----------------- " << vs.size() << endl;
  rep(i,vs.size())
    cout << vs[i] << endl;
  */
  REP(j,2,2+N)
    {
      Segment seg = Segment(vec[j].seg.p1 - vec[j].seg.p2,vec[j].seg.p2 - vec[j].seg.p2);
      Point rig = rotate(seg.p1,toRad(90.0));
      rig = (rig/abs(rig))*1000;
      vs.push_back(Segment(vec[j].seg.p1-rig,vec[j].seg.p1+rig));
      vs.push_back(Segment(vec[j].seg.p2-rig,vec[j].seg.p2+rig));
    }
}

//segment merge--------
bool merge_if_able(Segment &s, Segment t) {
  if (abs(cross(s.p2-s.p1, t.p2-t.p1)) > EPS) return false;
  if (ccw(s.p1, t.p1, s.p2) == +1 ||
      ccw(s.p1, t.p1, s.p2) == -1) return false; // not on the same line
  if (ccw(s.p1, s.p2, t.p1) == -2 ||
      ccw(t.p1, t.p2, s.p1) == -2) return false; // separated
  s = Segment(min(s.p1, t.p1), max(s.p2, t.p2));
  return true;
}
void merge_segments(vector<Segment>& segs) {
  for (int i = 0; i < segs.size(); ++i)
    if (segs[i].p2 < segs[i].p1)
      swap(segs[i].p2, segs[i].p1);
  for (int i = 0; i < segs.size(); ++i)
    for (int j = i+1; j < segs.size(); ++j)
      if (merge_if_able(segs[i], segs[j]))
        segs[j--] = segs.back(), segs.pop_back();
}
// -------------------

struct Pox
{
  int cur;
  double cost;
  Pox(int cur=inf,double cost=inf):cur(cur),cost(cost){}
  bool operator < (const Pox& a)const
  {
    return cost > a.cost;
  }
};

void dijkstra(vvE &G,int st,int ed)
{
  int n = G.size();
  double mincost[n];
  rep(i,n)mincost[i] = inf;
  mincost[st] = 0;
  priority_queue<Pox> Q;
  Q.push(Pox(st,0));

  while(!Q.empty())
    {
      Pox pox = Q.top(); Q.pop();

      if(pox.cur == ed)
	{
	  cout << setiosflags(ios::fixed) << setprecision(5) << pox.cost << endl;
	  return;
	}

      rep(i,G[pox.cur].size())
	{
	  int next = G[pox.cur][i].to;
	  double cost = G[pox.cur][i].cost;
	  if(!equals(mincost[next],pox.cost+cost) && mincost[next] > pox.cost + cost)
	    {
	      mincost[next] = pox.cost + cost;
	      Q.push(Pox(next,pox.cost+cost));
	    }
	}

    }
  cout << "Impossible" << endl;
}

void compute()
{
  vector<Segment> vs;
  toSegOnly(vs);

  /*
  cout << "vs------bef" << endl;
  rep(i,vs.size())
    {
      cout << vs[i] << endl;
    }
  
  
  rep(i,vs.size())
    if(!equals(vs[i].p1.x,vs[i].p2.x) && vs[i].p1.x > vs[i].p2.x)
      swap(vs[i].p1,vs[i].p2);
  */
  merge_segments(vs);  
  /*
  cout << "vs------aft" << endl;
  rep(i,vs.size())
    {
      cout << vs[i] << endl;
    }
  */

  vector<Point> ps;
  vvE G = segmentArrangementVer1(vs,ps);

  int st_index,ed_index;
  rep(i,ps.size())
    {
      //cout << "ps[" << i << "] = "<< ps[i] << endl;
      if(ps[i] == vec[0].seg.p1)st_index = i;
      if(ps[i] == vec[1].seg.p1)ed_index = i;
    }

  //cout << "st = " << st_index << endl;
  //cout << "ed = " << ed_index << endl;

  /*
  cout << "G-----" << endl;
  rep(i,G.size())
    {
      cout << "node " << i << endl;
      rep(j,G[i].size())
	{
	  cout << "(" << G[i][j].from << "," << G[i][j].to << "," << G[i][j].cost << ") ";
	}
      cout << endl;
    }
  */
  dijkstra(G,st_index,ed_index);
   
}

int main()
{
  int CNT = 1;
  while(cin >> N,N)
    {
      vec.clear();
      vec.resize(N+2);
      double x,y;
      rep(i,2)
	{
	  cin >> x >> y;
	  vec[i].seg.p1 = vec[i].seg.p2 = Point(x,y);
	  vec[i].type = 0;
	}
      rep(i,N)
	cin >> vec[2+i].seg.p1.x >> vec[2+i].seg.p1.y >> vec[2+i].seg.p2.x >> vec[2+i].seg.p2.y;
      cout << "Case " << CNT++ << ": ";
      compute();
    }
  return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 4500
final_rank: 4

code_snippet: #include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const double EPS=1e-6;
const double INF=1e77;
const double PI=acos(-1);

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	point &operator/=(double c){ x/=c; y/=c; return *this; }
	point operator+(const point &a)const{ return point(x+a.x,y+a.y); }
	point operator-(const point &a)const{ return point(x-a.x,y-a.y); }
	bool operator< (const point &a)const{ return x+EPS<a.x || abs(x-a.x)<EPS && y+EPS<a.y; }
	bool operator==(const point &a)const{ return abs(x-a.x)<EPS && abs(y-a.y)<EPS; }
};

point operator*(double c,const point &a){ return point(c*a.x,c*a.y); }

double dot(const point &a,const point &b){ return a.x*b.x+a.y*b.y; }

double cross(const point &a,const point &b){ return a.x*b.y-a.y*b.x; }

double abs(const point &a){ return sqrt(a.x*a.x+a.y*a.y); }

double abs2(const point &a){ return a.x*a.x+a.y*a.y; }

point rot(const point &a,double theta){ return point(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta)); }

struct line{
	point a,b;
	line(){}
	line(const point &a,const point &b):a(a),b(b){}
};

struct segment{
	point a,b;
	segment(){}
	segment(const point &a,const point &b):a(a),b(b){}
	operator line()const{ return line(a,b); }
};

point proj(const line &L,const point &p){ return L.a+dot(p-L.a,L.b-L.a)/abs2(L.b-L.a)*(L.b-L.a); }

enum{CCW=1,CW=-1,ON=0};
int ccw(const point &a,const point &b,const point &c){
	double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

bool cover(const segment &S,const point &p){
	return abs(cross(S.a-p,S.b-p))<EPS && dot(S.a-p,S.b-p)<EPS;
}

bool intersect(const segment &S1,const segment &S2){
	if(max(S1.a.x,S1.b.x)+EPS<min(S2.a.x,S2.b.x)
	|| max(S1.a.y,S1.b.y)+EPS<min(S2.a.y,S2.b.y)
	|| max(S2.a.x,S2.b.x)+EPS<min(S1.a.x,S1.b.x)
	|| max(S2.a.y,S2.b.y)+EPS<min(S1.a.y,S1.b.y)) return false;
	return ccw(S1.a,S1.b,S2.a)*ccw(S1.a,S1.b,S2.b)<=0
		&& ccw(S2.a,S2.b,S1.a)*ccw(S2.a,S2.b,S1.b)<=0;
}

point get_intersect(const segment &S1,const segment &S2){
	double a1=cross(S1.b-S1.a,S2.b-S2.a);
	double a2=cross(S1.b-S1.a,S1.b-S2.a);
	if(abs(a1)<EPS){
		if(cover(S1,S2.a)) return S2.a;
		if(cover(S1,S2.b)) return S2.b;
		if(cover(S2,S1.a)) return S1.a;
		return S1.b;
	}
	return S2.a+a2/a1*(S2.b-S2.a);
}

void arrangement(const vector<segment> &S,vector<point> &P,vector<int> *G,point s,point g){
	int n=S.size();
	P.clear();
	P.push_back(s); // 特別に追加する
	P.push_back(g); // 特別に追加する
	rep(i,n){
		P.push_back(S[i].a);
		P.push_back(S[i].b);
		rep(j,i) if(intersect(S[i],S[j])) P.push_back(get_intersect(S[i],S[j]));
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	rep(u,P.size()) G[u].clear();
	rep(i,n){
		vector<int> on;
		rep(u,P.size()) if(cover(S[i],P[u])) on.push_back(u);
		rep(j,(int)on.size()-1){
			int u=on[j],v=on[j+1];
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}
}

int main(){
	for(int cas=1,n;scanf("%d",&n),n;cas++){
		point s,g; scanf("%lf%lf%lf%lf",&s.x,&s.y,&g.x,&g.y);
		segment F[100];
		rep(i,n) scanf("%lf%lf%lf%lf",&F[i].a.x,&F[i].a.y,&F[i].b.x,&F[i].b.y);

		vector<segment> S;
		rep(i,n){
			point v=rot(F[i].b-F[i].a,PI/2); v/=abs(v);
			// start-electrode, goal-electrode
			if(cover(F[i],proj(F[i],s))) S.push_back(segment(s-1e4*v,s+1e4*v));
			if(cover(F[i],proj(F[i],g))) S.push_back(segment(g-1e4*v,g+1e4*v));
			// electrode rail
			S.push_back(segment(F[i].a-1e4*v,F[i].a+1e4*v));
			S.push_back(segment(F[i].b-1e4*v,F[i].b+1e4*v));
		}

		vector<point> P;
		static vector<int> G[30000];
		arrangement(S,P,G,s,g);

		int s_id=-1,g_id=-1;
		rep(u,P.size()){
			if(P[u]==s) s_id=u;
			if(P[u]==g) g_id=u;
		}

		// Dijkstra
		vector<double> d(P.size(),INF);
		d[s_id]=0;
		priority_queue< pair<double,int> > Q; Q.push(make_pair(0,s_id));
		while(!Q.empty()){
			double d_now=-Q.top().first;
			int u=Q.top().second; Q.pop();

			if(d[u]<d_now-EPS) continue;

			rep(i,G[u].size()){
				int v=G[u][i];
				double d_next=d[u]+abs(P[u]-P[v]);
				if(d_next+EPS<d[v]){
					d[v]=d_next;
					Q.push(make_pair(-d[v],v));
				}
			}
		}

		printf("Case %d: ",cas);
		if(d[g_id]<INF/2) printf("%.5f\n",d[g_id]); else puts("Impossible");
	}

	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3304
final_rank: 1

code_snippet: #include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const long double EPS=1e-7;
const long double INF=1e77;
const long double PI=acos(-1);

struct point{
	long double x,y;
	point():x(0),y(0){}
	point(long double x,long double y):x(x),y(y){}
	point &operator/=(long double c){ x/=c; y/=c; return *this; }
	point operator+(const point &a)const{ return point(x+a.x,y+a.y); }
	point operator-(const point &a)const{ return point(x-a.x,y-a.y); }
	bool operator< (const point &a)const{ return x+EPS<a.x || abs(x-a.x)<EPS && y+EPS<a.y; }
	bool operator==(const point &a)const{ return abs(x-a.x)<EPS && abs(y-a.y)<EPS; }
};

point operator*(long double c,const point &a){ return point(c*a.x,c*a.y); }

long double dot(const point &a,const point &b){ return a.x*b.x+a.y*b.y; }

long double cross(const point &a,const point &b){ return a.x*b.y-a.y*b.x; }

long double abs(const point &a){ return sqrt(a.x*a.x+a.y*a.y); }

long double abs2(const point &a){ return a.x*a.x+a.y*a.y; }

point rot(const point &a,long double theta){ return point(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta)); }

struct line{
	point a,b;
	line(){}
	line(const point &a,const point &b):a(a),b(b){}
};

struct segment{
	point a,b;
	segment(){}
	segment(const point &a,const point &b):a(a),b(b){}
	operator line()const{ return line(a,b); }
};

point proj(const line &L,const point &p){ return L.a+dot(p-L.a,L.b-L.a)/abs2(L.b-L.a)*(L.b-L.a); }

enum{CCW=1,CW=-1,ON=0};
int ccw(const point &a,const point &b,const point &c){
	long double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

bool cover(const segment &S,const point &p){
	return abs(cross(S.a-p,S.b-p))<EPS && dot(S.a-p,S.b-p)<EPS;
}

bool intersect(const segment &S1,const segment &S2){
	if(max(S1.a.x,S1.b.x)+EPS<min(S2.a.x,S2.b.x)
	|| max(S1.a.y,S1.b.y)+EPS<min(S2.a.y,S2.b.y)
	|| max(S2.a.x,S2.b.x)+EPS<min(S1.a.x,S1.b.x)
	|| max(S2.a.y,S2.b.y)+EPS<min(S1.a.y,S1.b.y)) return false;
	return ccw(S1.a,S1.b,S2.a)*ccw(S1.a,S1.b,S2.b)<=0
		&& ccw(S2.a,S2.b,S1.a)*ccw(S2.a,S2.b,S1.b)<=0;
}

point get_intersect(const segment &S1,const segment &S2){
	long double a1=cross(S1.b-S1.a,S2.b-S2.a);
	long double a2=cross(S1.b-S1.a,S1.b-S2.a);
	if(abs(a1)<EPS){
		if(cover(S1,S2.a)) return S2.a;
		if(cover(S1,S2.b)) return S2.b;
		if(cover(S2,S1.a)) return S1.a;
		return S1.b;
	}
	return S2.a+a2/a1*(S2.b-S2.a);
}

void arrangement(const vector<segment> &S,vector<point> &P,vector<int> *G,point s,point g){
	int n=S.size();
	P.clear();
	P.push_back(s); // テァツ可ケテ・ツ按・テ」ツ?ォティツソツステ・ツ環?」ツ?凖」ツつ?
	P.push_back(g); // テァツ可ケテ・ツ按・テ」ツ?ォティツソツステ・ツ環?」ツ?凖」ツつ?
	rep(i,n){
		P.push_back(S[i].a);
		P.push_back(S[i].b);
		rep(j,i) if(intersect(S[i],S[j])) P.push_back(get_intersect(S[i],S[j]));
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	rep(u,P.size()) G[u].clear();
	rep(i,n){
		vector<int> on;
		rep(u,P.size()) if(cover(S[i],P[u])) on.push_back(u);
		rep(j,(int)on.size()-1){
			int u=on[j],v=on[j+1];
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}
}

int main(){
	for(int cas=1,n;scanf("%d",&n),n;cas++){
		point s,g; scanf("%Lf%Lf%Lf%Lf",&s.x,&s.y,&g.x,&g.y);
		segment F[100];
		rep(i,n) scanf("%Lf%Lf%Lf%Lf",&F[i].a.x,&F[i].a.y,&F[i].b.x,&F[i].b.y);

		vector<segment> S;
		rep(i,n){
			point v=rot(F[i].b-F[i].a,PI/2); v/=abs(v);
			// start-electrode, goal-electrode
			if(cover(F[i],proj(F[i],s))) S.push_back(segment(s-1e4*v,s+1e4*v));
			if(cover(F[i],proj(F[i],g))) S.push_back(segment(g-1e4*v,g+1e4*v));
			// electrode rail
			S.push_back(segment(F[i].a-1e4*v,F[i].a+1e4*v));
			S.push_back(segment(F[i].b-1e4*v,F[i].b+1e4*v));
		}

		vector<point> P;
		static vector<int> G[50000];
		arrangement(S,P,G,s,g);

		int s_id=-1,g_id=-1;
		rep(u,P.size()){
			if(P[u]==s) s_id=u;
			if(P[u]==g) g_id=u;
		}

		// Dijkstra
		vector<long double> d(P.size(),INF);
		d[s_id]=0;
		priority_queue< pair<long double,int> > Q; Q.push(make_pair(0,s_id));
		while(!Q.empty()){
			long double d_now=-Q.top().first;
			int u=Q.top().second; Q.pop();

			if(d[u]<d_now-EPS) continue;

			rep(i,G[u].size()){
				int v=G[u][i];
				long double d_next=d[u]+abs(P[u]-P[v]);
				if(d_next+EPS<d[v]){
					d[v]=d_next;
					Q.push(make_pair(-d[v],v));
				}
			}
		}

		printf("Case %d: ",cas);
		if(d[g_id]<INF/2) printf("%.5Lf\n",d[g_id]); else puts("Impossible");
	}

	return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 4796
final_rank: 2

code_snippet: #include<iostream>
#include<queue>
#include<map>
#include<vector>
#include<cmath>
#include<complex>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define mp         make_pair
#define pb         push_back

template<class T> void pp(T a,int n){rep(i,n)cout<<a[i]<<" ";cout<<endl;}

typedef complex<double> P;
typedef pair<P,P>       Line;

const int N = 1000010;
const double eps = 1e-10;
const double PI  = acos(-1);
const double inf = 1e10;

namespace std{
  bool operator<(const P &a,const P &b){
    if (a.real()!=b.real())return a.real()<b.real();
    return a.imag() < b.imag();
  }
}

bool isp(P a,P b,P c){
  return abs(a-c)+abs(b-c) < abs(a-b) +eps;
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

double distance_lp(P a,P b,P c){
  return abs( cross(b-a,c-a))/abs(b-a);
}

bool is_intersected_ll(P a1,P a2,P b1,P b2){
  return !(fabs(cross(a1-a2,b1-b2))<eps);
}

P intersection_ll(P a1,P a2,P b1,P b2){
  P a= a2-a1,b=b2-b1;
  return a1+ a*cross(b,b1-a1)/cross(b,a);
}

P mapping(P a,P b){//mapping b to a
  double tmp = dot(a,b);
  tmp/=abs(a);
  return a/abs(a)*tmp;
}

P getp(P a,P b){
  P t=b-a;
  swap(t.real(),t.imag());
  t.real()*=-1;
  return t+a;
}

void connect(P a,P b,P c,vector<Line> &in){
  if (isp(a,b,c)){
    in.pb(mp(getp(a,b)-a+c,c));
  }else if (dot(b-a,c-a)>=0 && dot(a-b,c-b)>=0)
    in.pb(mp(mapping(b-a,c-a)+a,c));
  return;
}

void make(P a,P b,vector<Line> &all,vector<Line>&in){
  int n = all.size();
  rep(i,n){
    connect(all[i].first,all[i].second,a,in);
    connect(all[i].first,all[i].second,b,in);
  }
}

void per(vector<Line> &in,vector<Line> &in2){
  rep(i,in.size()){
    in2.pb(mp(getp(in[i].first,in[i].second),in[i].first));
    in2.pb(mp(getp(in[i].second,in[i].first),in[i].second));
  }
}

int getindex(P a,map<P,int> & M){
  int index = M.size();
  if (M.find(a) == M.end())M[a]=index;//,cout << a <<" " << index << endl;
  return M[a];
}

class state{
public:
  int now;
  double cost;
  bool operator<(const state&a)const{
    return cost > a.cost;
  }
};

vector<state> edge[N];
double cost[N];
double dijkstra(int s,int g,int n){
  rep(i,n)cost[i]=inf;
  priority_queue<state> Q;
  Q.push((state){s,0});
  cost[s]=0;
  while(!Q.empty()){
    state now = Q.top();Q.pop();
    if (cost[now.now] >now.cost)continue;
    //    cout << now.now <<" " << cost[now.now] << endl;
    if (now.now == g)return cost[now.now];
    rep(i,edge[now.now].size()){
      int nex=edge[now.now][i].now;
      double nec=cost[now.now]+edge[now.now][i].cost;
      if (nec < cost[nex]){
	cost[nex]=nec;
	Q.push((state){nex,nec});
      }
    }
  }
  return -1;
}


double solve(P s,P g,vector<Line> &in){
  vector<Line> in2;
  per(in,in2);
  make(s,g,in,in2);
  in.clear();

  vector<P> all;
  all.pb(s);
  all.pb(g);
  rep(i,in2.size()){
    all.pb(in2[i].first);
    all.pb(in2[i].second);
    REP(j,i+1,in2.size())
      if (is_intersected_ll(in2[i].first,in2[i].second,in2[j].first,in2[j].second))
	all.pb(intersection_ll(in2[i].first,in2[i].second,in2[j].first,in2[j].second));
  }
  sort(all.begin(),all.end());
  all.erase(unique(all.begin(),all.end()),all.end());

  rep(i,in2.size()){
    //    cout << in2[i].first <<" " << in2[i].second << endl;
  }

  map<P,int> M;
  rep(i,in2.size()){
    vector<P> l;
    rep(j,all.size())
      if (distance_lp(in2[i].first,in2[i].second,all[j])<eps)l.pb(all[j]);
    sort(l.begin(),l.end());
    //    pp(l,l.size());
    rep(i,(int)l.size()-1){
      int fr=getindex(l[i],M),to=getindex(l[i+1],M);
      double dist=abs(l[i]-l[i+1]);
      //      cout << l[i]<<" " << l[i+1]<<" " << dist << endl;
      edge[fr].pb((state){to,dist});
      edge[to].pb((state){fr,dist});
    }
  }

  double ans = dijkstra(getindex(s,M),getindex(g,M),M.size());
  rep(i,M.size())edge[i].clear();
  return ans;
}

main(){
  int n;
  int tc = 1;
  while(cin>>n && n){
    P s,g;
    cin>>s.real()>>s.imag()>>g.real()>>g.imag();
    vector<Line> in(n);
    rep(i,n){
      rep(j,2){
	cin>>in[i].first.real()>>in[i].first.imag();
	swap(in[i].first,in[i].second);
      }
    }
    double ans = solve(s,g,in);
    if (ans < 0)printf("Case %d: Impossible\n",tc++);
    else        printf("Case %d: %.5lf\n",tc++,ans);
  }
  return false;
}
accuracy: 1
time_ms: 780
memory_kb: 15000
final_rank: 8