Problem:
鏡の迷路
誇り高き勇者であるあなたは、ついに魔王の元へ辿り着こうとしていた。しかし、魔王がいる玉座の間に辿り着くためには、魔王が用意した最終マップをクリアしなければならない。
このマップにおいては、全てのものが、上空から見た二次元平面図のように変化してしまう。人間は、このマップにおいては、ただの点に変形してしまう。マップは、1本の直線によって、2つの区域に区切られている。そして、ある一方の区域に人がいるとき、もう一方の区域の、直線に対して線対称となる位置に、人の鏡像が映し出される。
2つの区域それぞれには、複数の建物が存在する。建物と言っても、このマップでは、いくつかの点を繋いで出来上がる多角形であり、辺で囲まれた内側、および辺上が建物の内部となる。建物は、人とは違い、別の区域に鏡像を作り出すことはない。
あなたがこのマップに侵入すると、魔王の魔法により、いずれかの建物の内部に拘束される。あなたは、拘束されている建物の内部に1つだけ存在する脱出点に移動することでしか、マップをクリアすることはできない。さらに、あなたは、魔王に呪いをかけられ、自身の動きを制限されている。その制限とは、あなたのいる位置、およびあなたの鏡像の位置が、いずれかの建物内部に存在しなければならないというものである。この制限さえ守れば、あなたは自由に建物内部を移動することができる。
さて、あなたは、一刻も早くこのマップをクリアし、世界を滅ぼさんとする魔王を打ち倒さなければならない。あなたの初期位置が与えられたとき、脱出点へ移動するための最短路の距離を求めよ。ただし、脱出点へ移動できない場合は、永遠マップから脱出することができず、朽ち果てていくのみである。
Input
入力は複数のデータセットから構成される。
各データセットの形式は次の通りである。
N
BUILDING
1
...
BUILDING
N
SX
SY
GX
GY
LX
1
LY
1
LX
2
LY
2
入力は、全て整数値である。
また、座標情報は、全て -10,000 <= x, y <= 10,000 であると仮定してよい。
N(1 <= N <= 100)は、建物の数である。その次に、N個の建物の情報が入力される。
BUILDING
i
は、次の形式で入力される多角形である。
M
X
1
Y
1
...
X
M
Y
M
M(3 <= M <= 50)は、多角形の頂点数を表す。
続いてM個の頂点、(X
i
, Y
i
)が反時計回りで入力される。
(X
i
, Y
i
)と(X
i+1
, Y
i+1
)の頂点を繋いだ線分が多角形の一辺である。
ただし、M番目の頂点とは、1番目の頂点が繋がる。
多角形の連続する3つの頂点は、一直線上に並ばないものと仮定してよい。
また、多角形の各辺は、隣り合う辺以外とは、接触・交差することはないように入力される。
各多角形は、他の多角形に、接触・交差・内包することはない。
建物の情報が入力された後、始点(SX, SY)、脱出点(GX, GY)の情報が入力される。
始点と脱出点は、共に同じ建物の内部に存在する。
ただし、始点と脱出点の鏡像は、必ずしも建物の内部に存在するとは限らないため注意してほしい。
この場合は、もちろんマップをクリアすることはできない。
始点と脱出点は、必ず異なる位置に存在する。
最後に、直線の情報が入力される。
直線は、直線上に存在する2つの点(LX
1
, LY
1
)と(LX
2
, LY
2
)により表される。
この2つの点は、必ず異なる位置に存在する。
直線は、いずれの建物とも、接触・交差しないものと仮定してよい。
入力の終わりは、0が1つだけの行で与えられる。
Output
各データセットごとに、始点から脱出点までの最短距離を出力せよ。
解答の誤差は 0.00000001 (10
-8
) を超えてはならない。
精度に関する条件を満たしていれば、小数点以下は何桁数字を出力しても構わない。
脱出点まで辿り着けない場合は、"impossible"と出力せよ。
Sample Input
2
3
1 1
2 2
1 2
3
-1 1
-1 2
-2 2
1 1 2 2
0 0 0 1
2
10
1 1
7 1
7 5
5 5
5 3
6 3
6 2
3 2
3 5
1 5
10
-1 1
-1 5
-3 5
-3 3
-2 3
-2 2
-5 2
-5 5
-7 5
-7 1
2 4 6 4
0 0 0 1
2
7
-7 0
-5 0
-4 3
-3 0
-1 0
-1 4
-7 4
3
1 0
7 0
7 4
3 1 5 2
0 0 0 1
0
Output for Sample Input
1.4142135623730951
8.0
impossible
以下の図はそれぞれサンプルの配置を示している。
図G-1、G-2では、赤の経路が勇者自身の経路を示し、青の経路が勇者の鏡像の経路を示す。
図G-3では、始点から脱出点まで辿り着くことはできない。
図G-1: 1番目のサンプル
図G-2: 2番目のサンプル
図G-3: 3番目のサンプル

Submitted solutions:

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };


typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}
//線分と線分の交点、平行な場合は端点両方
vector<Point> is_ss(Line s1, Line s2) {
	if (!isis_ss(s1, s2))return {};
	vector<Point> res;
	if (abs(cross(s1.b - s1.a, s2.b - s2.a)) < eps) {
		if (isis_sp(s1, s2.a)) res.push_back(s2.a);
		if (isis_sp(s1, s2.b)) res.push_back(s2.b);
		if (isis_sp(s2, s1.a)) res.push_back(s1.a);
		if (isis_sp(s2, s1.b)) res.push_back(s1.b);
	}
	else {
		res.push_back(is_ll(s1, s2));
	}
	return res;
}
using polygon = vector<Point>;
int is_in_polygon(polygon& poly, Point p) {
	ld sum = 0;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		if (isis_sp(e, p))return 0;
		sum += arg((pr - p) / (pl - p));
	}
	if (abs(sum) < pi / 2)return 2;
	return 1;
}
bool edge_in_polygon(polygon& poly, Line l) {
	Point s = l.a, t = l.b;
	if (is_in_polygon(poly, s) == 2 || is_in_polygon(poly, t) == 2)return false;
	vector<ld> ts;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		vector<Point> vp = is_ss(l, e);
		for (Point p : vp) {
			ld val = abs(p - s) / abs(t - s);
			ts.push_back(val);
		}
	}
	ts.push_back(0);
	ts.push_back(1);
	sort(all(ts));
	rep(i, ts.size() - 1) {
		ld x = (ts[i] + ts[i + 1]) / 2;
		Point c = s + (t - s) * x;
		if (is_in_polygon(poly, c) == 2)return false;
	}
	return true;
}

Point rev_p(Line l, Point p) {
	Point h = proj(l, p);
	return h + h - p;
}
Line rev_l(Line l, Line s) {
	return { rev_p(l,s.a),rev_p(l,s.b) };
}
polygon rev_poly(Line l, polygon poly) {
	rep(i, poly.size()) {
		poly[i] = rev_p(l, poly[i]);
	}
	reverse(all(poly));
	return poly;
}

int n;
void solve() {
	vector<polygon> b(n);
	rep(i, n) {
		int m; cin >> m;
		b[i].resize(m);
		rep(j, m) {
			int x, y; cin >> x >> y;
			b[i][j] = { (ld)x,(ld)y };
		}
	}
	int sx, sy, gx, gy; cin >> sx >> sy >> gx >> gy;
	Point ps = { (ld)sx,(ld)sy };
	Point pg = { (ld)gx,(ld)gy };
	Line l;
	int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
	l = { {(ld)x1,(ld)y1},{(ld)x2,(ld)y2} };
	Point rps = rev_p(l, ps);
	Point rpg = rev_p(l, pg);
	int chks = -1;
	int chkg = -1;
	int chk = -1;
	rep(i, n) {
		if (is_in_polygon(b[i], ps) < 2) {
			chk = i;
		}
		if (is_in_polygon(b[i], rps) < 2) {
			chks = i;
		}
		if (is_in_polygon(b[i], rpg) < 2) {
			chkg = i;
		}
	}
	assert(chk >= 0);
	if (chks == -1 || chks != chkg) {
		cout << "impossible\n"; return;
	}
	assert(chk != chks);
	polygon p1 = b[chk];
	polygon p2 = b[chks];
	p2 = rev_poly(l, p2);
	vector<Point> vp;
	vp.push_back(ps);
	vp.push_back(pg);
	for (Point p : p1) {
		if (is_in_polygon(p2, p) < 2)vp.push_back(p);
	}
	for (Point p : p2) {
		if (is_in_polygon(p1, p) < 2)vp.push_back(p);
	}
	vector<vector<ld>> cost(vp.size(), vector<ld>(vp.size()));
	rep(i, vp.size())rep(j, vp.size()) {
		if (abs(vp[i] - vp[j]) < eps) {
			cost[i][j] = 0; continue;
		}
		Line curl = { vp[i],vp[j] };
		if (edge_in_polygon(p1, curl) && edge_in_polygon(p2, curl)) {
			cost[i][j] = abs(vp[j] - vp[i]);
		}
		else {
			cost[i][j] = INF;
		}
	}
	vector<ld> dist(vp.size(), INF);
	dist[0] = 0;
	using speP = pair<ld, int>;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,0 });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (p.first > dist[id])continue;
		rep(to, vp.size()) {
			ld nval = p.first + cost[id][to];
			if (nval < dist[to]) {
				dist[to] = nval;
				q.push({ nval,to });
			}
		}
	}
	if (dist[1] == INF) {
		cout << "impossible\n";
	}
	else {
		cout << dist[1] << "\n";
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//init();
	//int t; cin >> t; rep(i, t)
	while (cin >> n, n) {
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 480
memory_kb: 12200
final_rank: 19

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 105
#define G_SIZE 2005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

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

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return 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;
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	Point p[2];
};

struct Edge{
	Edge(int arg_to,double arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to;
	double cost;
};

struct Info{
	Info(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}

	int node_id;
	double sum_dist;
};


int N;
int base_index,rev_index;
double min_dist[G_SIZE];
Polygon POLYGON[SIZE],REV,BASE;
Point start,goal,rev_start,rev_goal;
Line LINE;
vector<Edge> G[G_SIZE];



Point calc_Reflection_Point(double x1,double y1,double x2,double y2,double xp,double yp){

	Point ret;

	bool X_FLG = false,Y_FLG = false;
	double slope;

	if(y1 == y2){
		X_FLG = true;
	}else if(x1 == x2){
		Y_FLG = true;
	}else{
		slope = (y2-y1)/(x2-x1);
	}

	if(X_FLG){
		ret.x = xp,ret.y=y1;
	}else if(Y_FLG){
		ret.x = x1,ret.y = yp;
	}else{
		ret.x = (yp*(x2-x1)*(y2-y1)+xp*(x2-x1)*(x2-x1)-y1*(y2-y1)*(x2-x1)+x1*(y2-y1)*(y2-y1))/((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
		ret.y = ((x1-x2)*ret.x+yp*(y2-y1)+xp*(x2-x1))/(y2-y1);
	}
	ret.x = 2*ret.x-xp;
	ret.y = 2*ret.y-yp;

	return ret;
}

Point calc_Reflection_Point(Line line,Point point){

	return calc_Reflection_Point(line.p[0].x,line.p[0].y,line.p[1].x,line.p[1].y,point.x,point.y);
}




int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}


Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

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

double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[0].y-A.p[1].y)/(A.p[0].x-A.p[1].x);
	}
}

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

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

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


double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//★★点と線分の距離★★
double getDistanceSP(Line l,Point p){
	if(dot(l.p[1]-l.p[0],p-l.p[0]) < 0.0) return abs(p-l.p[0]);
	if(dot(l.p[0]-l.p[1],p-l.p[1]) < 0.0) return abs(p-l.p[1]);
	return getDistanceLP(l,p);
}

//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}


bool contains(Polygon g,Line l){

	if(contains(g,l.p[0]) == 0 || contains(g,l.p[1]) == 0){

		return false;
	}

	Polygon TMP;

	TMP.push_back(l.p[0]);
	TMP.push_back(l.p[1]);

	for(int i = 0; i < g.size(); i++){
		Line tmp_line = Line(g[i],g[(i+1)%g.size()]);

		if(is_Cross(tmp_line,l)){

			TMP.push_back(calc_Cross_Point(l,tmp_line));
		}
	}

	sort(TMP.begin(),TMP.end());
	TMP.erase(unique(TMP.begin(),TMP.end()),TMP.end());

	for(int i = 0; i < TMP.size()-1; i++){

		Point mid = Point((TMP[i].x+TMP[i+1].x)/2,(TMP[i].y+TMP[i+1].y)/2);
		if(contains(g,mid) == 0){

			return false;
		}
	}

	return true;
}

bool is_OK(Line A){

	return contains(POLYGON[base_index],A) && contains(REV,A);
}

void func(){

	REV.clear();
	BASE.clear();

	for(int i = 0; i < SIZE; i++){

		POLYGON[i].clear();
	}

	for(int i = 0; i < G_SIZE; i++){

		G[i].clear();
	}

	int num_points;
	double X,Y;

	for(int i = 0; i < N; i++){

		scanf("%d",&num_points);

		for(int loop = 0; loop < num_points; loop++){

			scanf("%lf %lf",&X,&Y);

			POLYGON[i].push_back(Point(X,Y));
		}
	}

	scanf("%lf %lf %lf %lf",&start.x,&start.y,&goal.x,&goal.y);
	scanf("%lf %lf %lf %lf\n",&LINE.p[0].x,&LINE.p[0].y,&LINE.p[1].x,&LINE.p[1].y);

	//startがあるポリゴンを探す
	for(int i = 0; i < N; i++){

		if(contains(POLYGON[i],start) != 0){

			base_index = i;
			break;
		}
	}

	//少なくとも、rev_startとrev_goalが同じポリゴンの中にあるか調べる
	rev_start = calc_Reflection_Point(LINE,start);
	rev_goal = calc_Reflection_Point(LINE,goal);

	int rev_start_index = -1,rev_goal_index = -1;

	for(int i = 0; i < N; i++){

		if(contains(POLYGON[i],rev_start) != 0){

			rev_start_index = i;
			break;
		}
	}

	if(rev_start_index == -1){

		printf("impossible\n");
		return;
	}

	for(int i = 0; i < N; i++){

		if(contains(POLYGON[i],rev_goal) != 0){

			rev_goal_index = i;
			break;
		}
	}

	if(rev_start_index != rev_goal_index){

		printf("impossible\n");
		return;
	}

	rev_index = rev_start_index;

	//POLYGON[rev_index]の線対称ポリゴン作成
	for(int i = 0; i < POLYGON[rev_index].size(); i++){

		REV.push_back(calc_Reflection_Point(LINE,POLYGON[rev_index][i]));
	}

	BASE.push_back(start);
	BASE.push_back(goal);

	for(int i = 0; i < POLYGON[base_index].size(); i++){

		BASE.push_back(POLYGON[base_index][i]);
	}

	for(int i = 0; i < REV.size(); i++){

		BASE.push_back(REV[i]);
	}

	//POLYGON[base_index]と、REVの交点を追加する
	for(int i = 0; i < POLYGON[base_index].size(); i++){
		Line A = Line(POLYGON[base_index][i],POLYGON[base_index][(i+1)%POLYGON[base_index].size()]);
		for(int k = 0; k < REV.size(); k++){
			Line B = Line(REV[k],REV[(k+1)%REV.size()]);

			if(!is_Cross(A,B))continue;

			BASE.push_back(calc_Cross_Point(A,B));
		}
	}

	sort(BASE.begin(),BASE.end());
	BASE.erase(unique(BASE.begin(),BASE.end()),BASE.end());

	int V = BASE.size();

	int start_index,goal_index;

	for(int i = 0; i < V; i++){

		if(BASE[i] == start){

			start_index = i;

		}else if(BASE[i] == goal){

			goal_index = i;
		}
	}

	//エッジをあらかじめ計算しておく
	for(int i = 0; i < V-1; i++){
		for(int k = i+1; k < V; k++){

			double tmp_dist = calc_dist(BASE[i],BASE[k]);

			if(is_OK(Line(BASE[i],BASE[k]))){

				G[i].push_back(Edge(k,tmp_dist));
				G[k].push_back(Edge(i,tmp_dist));
			}
		}
	}

	for(int i = 0; i < V; i++){

		min_dist[i] = HUGE_NUM;
	}

	min_dist[start_index] = 0;

	priority_queue<Info> Q;
	Q.push(Info(start_index,0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > min_dist[Q.top().node_id]+EPS){

			Q.pop();

		}else if(Q.top().node_id == goal_index){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].cost;

				if(min_dist[next_node] > next_dist+EPS){
					min_dist[next_node] = next_dist;
					Q.push(Info(next_node,next_dist));
				}
			}

			Q.pop();
		}
	}

	printf("impossible\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 3452
final_rank: 13

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;

template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,const pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,const vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    static bool comp(const P &p1,const P &p2){
        if(p1.real()==p2.real()){return p1.imag()<p2.imag();}
        return p1.real()<p2.real();
    }
    
    static bool comp_y(const P &p1,const P &p2){
        if(p1.imag()==p2.imag()){return p1.real()<p2.real();}
        return p1.imag()<p2.imag();
    }
    
    static bool eqls(const P &p1,const P &p2){return abs(p1-p2)<EPS;}
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){
        vec/=abs(vec); p1/=vec; p2/=vec;
        return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);
    }
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){
        if(dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS){return false;}
        if(dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS){return false;}
        return intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);
    }
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){
        if(dot(p2-p1,x-p1)<-EPS){return abs(x-p1);}
        if(dot(p1-p2,x-p2)<-EPS){return abs(x-p2);}
        return distLP(p1,p2,x);
    }
    
    D distSS(P p1,P p2,P p3,P p4){
        if(intersectSS(p1,p2,p3,p4)){return 0.0;}
        return min({distSP(p1,p2,p3),distSP(p1,p2,p4),
            distSP(p3,p4,p1),distSP(p3,p4,p2)});
    }
    
    P crosspointLL(P p1,P p2,P vec){
        if(abs(cross(p2-p1,vec))<EPS){return vec;}
        return vec*cross(p2-p1,p2)/cross(p2-p1,vec);
    }
    
    P crosspointLL(P p1,P p2,P p3,P p4){
        return p4+crosspointLL(p1-p4,p2-p4,p3-p4);
    }
    
    P crosspointSS(P p1,P p2,P p3,P p4){
        if(distSP(p1,p2,p3)<EPS){return p3;}
        if(distSP(p1,p2,p4)<EPS){return p4;}
        return crosspointLL(p1,p2,p3,p4);
    }
    
    bool intersectShL(P p1,P p2,P vec){
        vec/=abs(vec);
        return intersectSL(p1,p2,vec) &&
        crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;
    }
    
    bool intersectShL(P p1,P p2,P p3,P p4){
        return intersectShL(p1-p3,p2-p3,p4-p3);
    }
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        int s=1;
        vector<bool> cnt(s,false);
        for(int i=0;i<(int)poly.size();i++){
            int k=(i+1)%poly.size();
            if(distSP(poly[i],poly[k],p)<EPS){return 0;}
            for(int j=0;j<s;j++){
                if(intersectShL(poly[i],poly[k],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<s;j++){if(cnt[j]){in++;}}
        return in>s/2?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=0;i<(int)poly.size();i++){
            int j=(i+1)%poly.size();
            if(cross(p2-p1,poly[i]-p1)>-EPS){ret.push_back(poly[i]);}
            if(intersectSL(poly[i],poly[j],p1,p2) &&
               distLP(p1,p2,poly[i])>EPS && distLP(p1,p2,poly[j])>EPS){
                ret.push_back(crosspointLL(poly[i],poly[j],p1,p2));
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<(int)poly.size();i++){
            ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);
        }
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        auto fnc=[&](){
            for(auto &I:pts){
                if(!ret.empty() && I==ret.back()){continue;}
                while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){
                    ret.pop_back();
                }
                ret.push_back(I);
            }
        };
        fnc();
        reverse(pts.begin(),pts.end());
        fnc();
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){
            if(distSP(p1,p2,I)<EPS){ret.push_back(I);}
        }
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){
        return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));
    }
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<(int)poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        int N=pt.size();
        for(int i=1;i<N;i<<=1){
            for(int j=0;i+j<N;j+=i*2){
                int m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(int k=j;k<m;k++){l=max(l,pt[k].real());}
                for(int k=0;m+k<N && k<i;k++){r=min(r,pt[m+k].real());}
                for(int k=0;m+k<N && k<i;k++){
                    if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}
                }
                int idx=0;
                for(int k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    int M=R.size();
                    while(idx<M && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(int s=idx;s<M && R[s].imag()-pt[k].imag()<ret;s++){
                        ret=min(ret,abs(R[s]-pt[k]));
                    }
                }
                auto ed=(j+i*2<N?pt.begin()+j+2*i:pt.end());
                inplace_merge(pt.begin()+j,pt.begin()+m,ed,comp_y);
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<(int)pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    void segment_arrangement(const vector<pair<P,P>> &L,vector<pair<int,int>> &seg,vector<P> &pt){
        int N=L.size();
        for(int i=0;i<N;i++){
            pt.push_back(L[i].F);
            pt.push_back(L[i].S);
            for(int j=i+1;j<N;j++){
                if(intersectSS(L[i].F,L[i].S,L[j].F,L[j].S)){
                    pt.push_back(crosspointSS(L[i].F,L[i].S,L[j].F,L[j].S));
                }
            }
        }
        auto le=[](P a,P b){return eqls(a,b)?false:comp(a,b);};
        sort(pt.begin(),pt.end(),le);
        pt.erase(unique(pt.begin(),pt.end(),eqls),pt.end());
        for(auto &I:L){
            vector<pair<D,int>> on;
            for(int j=0;j<(int)pt.size();j++){
                if(distSP(I.F,I.S,pt[j])<EPS){
                    on.emplace_back(abs(pt[j]-I.F),j);
                }
            }
            sort(on.begin(),on.end());
            for(int j=1;j<(int)on.size();j++){
                seg.emplace_back(on[j-1].S,on[j].S);
            }
        }
        sort(seg.begin(),seg.end());
        seg.erase(unique(seg.begin(),seg.end()),seg.end());
    }
    
    vector<P> convex_of_segments(const vector<pair<P,P>> &L){
        vector<pair<int,int>> seg;
        vector<P> pt;
        segment_arrangement(L,seg,pt);
        vector<vector<int>> edge(pt.size());
        for(auto &I:seg){
            edge[I.F].push_back(I.S);
            edge[I.S].push_back(I.F);
        }
        vector<P> ret;
        function<void(int,int)> dfs=[&](int v,int pre){
            if(pre!=-1 && v==0){return;}
            ret.push_back(pt[v]);
            vector<pair<D,int>> nx;
            for(auto &u:edge[v]){
                D a=arg((pt[u]-pt[v])/(pre==-1 || eqls(pt[v],pt[pre])?P(1):pt[v]-pt[pre]));
                if(abs(a+PI)<EPS){a=PI;}
                nx.emplace_back(a,u);
            }
            sort(nx.begin(),nx.end());
            dfs(nx[0].S,v);
        };
        dfs(0,-1);
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;

//BEGIN CUT HERE
template <typename T>
vector<T> dijkstra(int s,vector<vector<pair<int, T> > > & G){
    const T INF = numeric_limits<T>::max();
    using P = pair<T, int>;
    int n=G.size();
    vector<T> d(n,INF);
    vector<int> b(n,-1);
    priority_queue<P,vector<P>,greater<P> > q;
    d[s]=0;
    q.emplace(d[s],s);
    while(!q.empty()){
        P p=q.top();q.pop();
        int v=p.second;
        if(d[v]<p.first) continue;
        for(auto& e:G[v]){
            int u=e.first;
            T c=e.second;
            if(d[u]>d[v]+c){
                d[u]=d[v]+c;
                b[u]=v;
                q.emplace(d[u],u);
            }
        }
    }
    return d;
}
//END CUT HERE

bool good(P l1,P l2,vector<P> &p1,vector<P> &p2){
    vector<P> con={l1,l2};
    for(int i=1;i<=p1.size();i++){
        if(intersectSS(l1,l2,p1[i-1],p1[i%p1.size()])){
            con.push_back(crosspointSS(l1,l2,p1[i-1],p1[i%p1.size()]));
        }
    }
    for(int i=1;i<=p2.size();i++){
        if(intersectSS(l1,l2,p2[i-1],p2[i%p2.size()])){
            con.push_back(crosspointSS(l1,l2,p2[i-1],p2[i%p2.size()]));
        }
    }
    sort(con.begin(),con.end(),[&](P a,P b){return abs(l1-a)<abs(l1-b);});
    for(int i=1;i<con.size();i++){
        P m=(con[i-1]+con[i])/(D)2;
        if(contain(p1,m)==-1 || contain(p2,m)==-1){return false;}
    }
    return true;
}


int main(){
    ll n;
    while(cin>>n,n){
        vector<vector<P>> A(n);
        for(auto &I:A){
            ll m;
            cin>>m;
            I.resize(m);
            cin>>I;
        }
        P s,g;
        cin>>s>>g;
        P l1,l2;
        cin>>l1>>l2;
        vector<P> pl,pl2;
        for(auto &I:A){
            if(contain(I,s)>-1 && contain(I,g)>-1){pl=I;}
            if(contain(I,reflect(l1,l2,s))>-1 && contain(I,reflect(l1,l2,g))>-1){pl2=I;}
        }
        if(pl.empty() || pl2.empty()){
            cout<<"impossible"<<endl;
            continue;
        }
        for(auto &I:pl2){I=reflect(l1,l2,I);}
        reverse(pl2.begin(),pl2.end());
        vector<P> pts=pl;
        for(auto &I:pl2){pts.push_back(I);}
        pts.push_back(s);
        pts.push_back(g);
        ll K=pts.size();
        vector<vector<pair<int,D>>> edge(K);
        for(int i=0;i<K;i++){
            for(int j=0;j<K;j++){
                if(good(pts[i],pts[j],pl,pl2)){
                    edge[i].push_back({j,abs(pts[i]-pts[j])});
                }
            }
        }
        D ans=dijkstra(K-2,edge)[K-1];
        if(ans>INF){cout<<"impossible"<<endl;}
        else{cout<<fixed<<setprecision(12)<<ans<<endl;}
    }
    
    return 0;
}
accuracy: 1
time_ms: 3950
memory_kb: 3456
final_rank: 20

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;

using ld = double;
using Point =  complex<ld>;
const ld eps = 1e-9;
const ld pi = acos(-1.0);

bool eq(ld a, ld b) {
	return (abs(a - b) < eps);
}

bool cmp(Point x,Point y){
	if(eq(x.real(),y.real()))return x.imag()<y.imag();
	return x.real()<y.real();
}

bool eqq(Point x,Point y){
	return eq(x.real(),y.real())&&eq(x.imag(),y.imag());
}
//内積
ld dot(Point a, Point b) {
	return real(conj(a)*b);
}
//外積
ld cross(Point a, Point b) {
	return imag(conj(a)*b);
}


//線分
//直線にするなら十分通い２点を端点とすればよい
class Line {
public:
	Point a, b;
};
//円
class Circle {
public:
	Point p;
	ld r;
};
//3点の位置関係
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//a,b,cが反時計回り
	if (cross(b, c) < -eps)return -1;//a,b,cが時計回り
	if (dot(b, c) < 0)return 2;//c,a,bの順に一直線
	if (norm(b) < norm(c))return -2;//a,b,cの順に一直線
	return 0;//a,c,bの順に一直線
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a)*cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
bool isis_ss(Line s, Line t) {
    if (isis_sp(t, s.a) || isis_sp(t, s.b))return false;
	if (isis_sp(s, t.a) || isis_sp(s, t.b) )return true;
	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}

Point cont(Line l, Point p){
	return 2.0*proj(l, p) - p;
}

//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}

bool included(vector<Point> pol, Point p){
    int n=pol.size();
    ld sum=0;
    rep(i,n){
        Point cur=pol[i], nxt=pol[(i+1)%n];
        if(isis_sp({cur,nxt},p))return true;
        sum+=arg((nxt-p)/(cur-p));
    }
    return abs(sum)>1;
}

void solve(int n){
    vector<vector<Point>> pols(n);
    rep(i,n){
        int m;
        cin>>m;
        rep(j,m){
            int x,y;
            cin>>x>>y;
            pols[i].push_back(Point(x,y));
        }
    }
    Point s,t;
    int x,y;
    cin>>x>>y;
    s = Point(x,y);
    cin>>x>>y;
    t = Point(x,y);
    Line l;
    cin>>x>>y;
    l.a = Point(x,y);
    cin>>x>>y;
    l.b = Point(x,y);
    vector<Point> front,back;
    rep(i,n){
        if(isis_ls(l,{s,pols[i][0]})){
            rep(j,pols[i].size())pols[i][j]=cont(l, pols[i][j]);
            if(included(pols[i],s)&&included(pols[i],t))back=pols[i];
        }
        else if(included(pols[i],s)&&included(pols[i],t))front=pols[i];
    }
    reverse(back.begin(),back.end());
    if(front.size()==0||back.size()==0){
        cout<<"impossible"<<endl;
        return ;
    }

    vector<Point> points;
    for(auto p : front)points.push_back(p);
    for(auto p : back)points.push_back(p);
    points.push_back(s);points.push_back(t);
    n = points.size();
    int f = front.size(), b=back.size();
    vector<pair<int,ld>> v[n];
    rep(i,n){
        if(!included(back,points[i])||!included(front,points[i]))continue;
        rep(j,i){
            if(!included(back,points[j])||!included(front,points[j]))continue;
            Line seg = Line{points[i],points[j]};
            bool ok=true;
            rep(k,f){
                if(isis_ss(seg, {front[k], front[(k+1)%f]}))ok=false;
            }
            rep(k,b){
                if(isis_ss(seg, {back[k], back[(k+1)%b]}))ok=false;
            }
            Point mid = (points[i]+points[j])*.5;
            if(!included(front, mid)||!included(back, mid))ok=false;
            if(ok)v[i].emplace_back(j,abs(points[i]-points[j]));
            if(ok)v[j].emplace_back(i,abs(points[i]-points[j]));
        }
    }
    vector<ld> dist(n,inf);
    dist[f+b]=0;
    using Pa = pair<ld,int>;
    priority_queue<Pa,vector<Pa>,greater<Pa>> que;
    que.push({0,f+b});
    while(que.size()){
        auto pa = que.top();que.pop();
        ld d=pa.first;int cur=pa.second;
        if(dist[cur]+eps<d)continue;
        for(auto to : v[cur]){
            if(dist[to.first]>dist[cur]+to.second){
                dist[to.first]=dist[cur]+to.second;
                que.emplace(dist[to.first], to.first);
            }
        }
    }
    if(dist[f+b+1]>1e9)cout<<"impossible"<<endl;
    else cout<<dist[f+b+1]<<endl;
}

int main(){
    int n;
    cout<<fixed<<setprecision(10);
    while(cin>>n,n!=0)solve(n);
    return 0;
}
accuracy: 1
time_ms: 360
memory_kb: 3520
final_rank: 15

code_snippet: #include <iostream>
#include <complex>
#include <cstdio>
#include <utility>
#include <vector>
#include <queue>
using namespace std;
typedef complex<double> P;
typedef pair<P,P> L;
typedef vector<P> Poly;
#define X real()
#define Y imag()
#define EPS (1e-10)
#define INF (1e15)

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

double dot(P a, P b){
  return a.X * b.X + a.Y * b.Y;
}
double cross(P a, P b){
  return a.X * b.Y - a.Y * b.X;
}

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) < -EPS ) return +2;
  if( abs(b) + EPS < abs(c) ) return -2;
  return 0;
}

bool is_cross(L a, L b){
  if(ccw(a.first,a.second,b.first)*ccw(a.first,a.second,b.second) < 0 &&
     ccw(b.first,b.second,a.first)*ccw(b.first,b.second,a.second) < 0) return true;
  return false;
}

P projection(P a, P b){
  //ベクトルaにのベクトルbに対する正射影ベクトル
  return dot(a, b)/abs(b)/abs(b)*b;
}

P line_symmetry(L l, P p){
  //点pと直線lに対して線対称な点
  return p + (l.first - p + projection(p-l.first,l.second-l.first))*2.0;
}

int in_poly(P a, Poly p){
  int n = p.size(), c = 0;
  p.push_back(p[0]);
  for(int i = 0; i < n; ++i){
    P s = p[i]-a, t = p[i+1]-a;
    if(!ccw(s,t,P(0,0))) return 1;//辺上
    if(s.Y > t.Y + EPS) swap(s,t);
    if((s.Y*t.Y < -EPS || (s.Y*t.Y < EPS && t.Y > EPS)) && cross(s,t) < EPS) ++c;
  }
  if(c%2) return 2;//内部
  return 0;//外部
}

double dijkstra(vector< vector<double> > &G){
  int n = G.size();
  vector<double> d(n,INF);
  priority_queue< pair<double,int> > wait;
  wait.push(make_pair(0,0));
  while(!wait.empty()){
    double dist = -wait.top().first;
    int v = wait.top().second;
    wait.pop();
    if(d[v] <= dist) continue;
    d[v] = dist;
    for(int i = 0; i < n; ++i){
      if(dist + G[v][i] < d[i]){
        wait.push(make_pair(-dist - G[v][i],i));
      }
    }
  }
  return d[1];
}

vector< vector<double> > make_graph(P start, P goal, Poly q, Poly p){
  int n = p.size() + q.size() + 2;
  vector< vector<double> > G(n, vector<double>(n,INF));

  Poly S;
  S.push_back(start);
  S.push_back(goal);
  for(int i = 0; i < q.size(); ++i) S.push_back(q[i]);
  for(int i = 0; i < p.size(); ++i) S.push_back(p[i]);
  /*
  for(int i = 0; i < n; ++i)
    cout << S[i] << endl;
  */
  vector<L> E;
  for(int i = 0; i < q.size(); ++i)
    E.push_back(make_pair(q[i],q[(i+1)%q.size()]));
  for(int i = 0; i < p.size(); ++i)
    E.push_back(make_pair(p[i],p[(i+1)%p.size()]));

  for(int i = 0; i < n; ++i){
    for(int j = i; j < n; ++j){
      if(in_poly((S[i]+S[j])/2.0,q) && in_poly((S[i]+S[j])/2.0,p)){
        bool f = true;
        for(int k = 0; k < E.size(); ++k){
          if((ccw(S[i],S[j],E[k].first) == 0 && abs(S[i]-E[k].first) > EPS && abs(S[j]-E[k].first) > EPS) ||
             (ccw(S[i],S[j],E[k].second) == 0 && abs(S[i]-E[k].second) > EPS && abs(S[j]-E[k].second) > EPS)){
            f = false;
            break;
          }
          if(is_cross(L(S[i],S[j]),E[k])){
            f = false;
            break;
          }
        }
        if(f){
          G[i][j] = abs(S[i]-S[j]);
          G[j][i] = G[i][j];
        }
      }
    }
  }
  return G;
}

int main(){
  int N, M;
  while(cin >> N, N){
    double x, y;
    vector<Poly> polys(N);
    for(int i = 0; i < N; ++i){
      cin >> M;
      for(int j = 0; j < M; ++j){
        cin >> x >> y;
        polys[i].push_back(P(x,y));
      }
    }
    cin >> x >> y;
    P start(x,y);
    cin >> x >> y;
    P goal(x,y);
    double x_, y_;
    cin >> x >> y >> x_ >> y_;
    L l(P(x,y),P(x_,y_));
    P start_ = line_symmetry(l,start);;
    Poly p, q;
    bool f = false, g = false;
    for(int i = 0; i < N; ++i){
      if(in_poly(start,polys[i])){
        p = polys[i];
        f = true;
      }
      if(in_poly(start_,polys[i])){
        q = polys[i];
        g = true;
      }
    }
    if(!(f&&g)){
      cout << "impossible" << endl;
      continue;
    }
    for(int i = 0; i < q.size(); ++i){
      q[i] = line_symmetry(l,q[i]);
    }
    vector< vector<double> > G = make_graph(start,goal,q,p);

    /*
    for(int i = 0; i < G.size(); ++i){
      for(int j = 0; j < G.size(); ++j){
        if(G[i][j] >= INF) cout << " INF  | ";
        else printf("%.3f | ",G[i][j]);
      }cout << endl;
    }
    */
    double ans = dijkstra(G);
    if(ans >= INF) cout << "impossible" << endl;
    else printf("%.12f\n",ans);
  }
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3424
final_rank: 10

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

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

namespace std{
	bool operator < (const P &a, const P &b){
		return (a.X!=b.X)? a.X<b.X : a.Y<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(norm(b) < norm(c)) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSP(const L& s, const P& p){
    return EQ(cross(s[0]-p, s[1]-p), 0) && dot(s[0]-p, s[1]-p)<EPS;
}
bool intersectSS(const L& s, const L& t){
    for(int i=0; i<2; i++){
        for(int j=0; j<2; j++){
            if(s[i]==t[j]) return true;
        }
    }
    return ( ccw(s[0],s[1],t[0]) *ccw(s[0],s[1],t[1]) <= 0 ) &&
        ( ccw(t[0],t[1],s[0]) *ccw(t[0],t[1],s[1]) <= 0 );
}

P projection(const L& l, const P& p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L& l, const P& p) {
  return p + 2.0*(projection(l, p) -p);
}

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

bool in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int cn=0;
    for(int i=0; i<n; i++){
        if(intersectSP(L(poly[i], poly[(i+1)%n]), p)){
            return true;
        }
    }
    L ray(p, p+P(INF, 0));
    for(int i=0; i<n; i++){
        if((poly[i].Y <= p.Y && poly[(i+1)%n].Y > p.Y) ||
           (poly[i].Y > p.Y && poly[(i+1)%n].Y <= p.Y)){
            if(intersectSS(ray, L(poly[i],poly[(i+1)%n]))){
                cn++;
            }
        }
    }
    return cn%2 != 0;
}

bool isVisible(const L &l, const vector<VP> &poly){
	VP cp;
	for(int r=0; r<(int)poly.size(); r++){
    	int n = poly[r].size();
    	for(int i=0; i<n; i++){
    	    L edge(poly[r][i], poly[r][(i+1)%n]);
    	    if(!isParallel(l, edge) && intersectSS(l, edge)){
    	        cp.push_back(crosspointLL(l, edge));
    	    }
    	}
    }
    sort(cp.begin(), cp.end());
    cp.erase(unique(cp.begin(), cp.end()), cp.end());
    
    bool ret = true;
    for(int r=0; r<(int)poly.size() && ret ; r++){
    	for(int i=0; i<(int)cp.size()-1; i++){
    	    if(!in_poly((cp[i]+cp[i+1])/2.0, poly[r])){
    	        ret = false;
    	        break;
    	    }
    	}
    }
    return ret;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;
        
        vector<VP> building(n);
        for(int i=0; i<n; i++){
        	int m;
        	cin >> m;
        	building[i].resize(m);
        	for(int j=0; j<m; j++){
        		int x,y;
        		cin >> x >> y;
        		building[i][j] = P(x,y);
        	}
        }
        int sx,sy, gx,gy;
        int lx1, ly1, lx2, ly2;
        cin >>sx>>sy>>gx>>gy>>lx1>>ly1>>lx2>>ly2;
        P s(sx, sy), g(gx, gy);
        L axis(P(lx1, ly1), P(lx2, ly2));
        if(ccw(axis[0], axis[1], s) < 0) swap(axis[0], axis[1]);
        
        vector<VP> poly(2);
        for(int i=0; i<n; i++){
        	if(ccw(axis[0], axis[1], building[i][0]) > 0){
        		if(in_poly(s, building[i])){
        			poly[0] = building[i];
        		}
        	}else{
        		if(in_poly(reflection(axis, s), building[i])){
        			if(in_poly(reflection(axis, g), building[i])){
        				poly[1] = building[i];
        			}else{
        				break;
        			}
        		}
        	}
        }
        if(poly[1].empty()){
        	cout << "impossible" << endl;
        	continue;
        }
        
        reverse(poly[1].begin(), poly[1].end());
        for(int i=0; i<(int)poly[1].size(); i++){
        	poly[1][i] = reflection(axis, poly[1][i]);
        }
        VP cp;
        cp.reserve(100);
        cp.push_back(s);
        cp.push_back(g);
        for(int r=0; r<2; r++){
        	int spr = poly[r].size();
        	for(int i=0; i<spr; i++){
        		if(ccw(poly[r][i], poly[r][(i+1)%spr], poly[r][(i+2)%spr]) == -1){
        			if(in_poly(poly[r][(i+1)%spr], poly[1-r])){
        				cp.push_back(poly[r][(i+1)%spr]);
        			}
        		}
        	}
        }
        
        int sc = cp.size();
        vector<vector<double> > adj(sc, vector<double>(sc, INF));
        for(int i=0; i<sc; i++){
        	for(int j=i+1; j<sc; j++){
        		if(isVisible(L(cp[i], cp[j]), poly)){
        			adj[i][j] = adj[j][i] = abs(cp[i]-cp[j]);
        		}
        	}
        }
        for(int k=0; k<sc; k++){
        	for(int i=0; i<sc; i++){
        		for(int j=0; j<sc; j++){
        			adj[i][j] = min(adj[i][j], adj[i][k]+adj[k][j]);
        		}
        	}
        }
        if(adj[0][1]==INF){
        	cout << "impossible" << endl;
        }else{
        	cout << fixed;
        	cout << setprecision(10);
        	cout << adj[0][1] << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 3320
final_rank: 11

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;

const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

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

namespace std{
	bool operator < (const P &a, const P &b){
		return (a.X!=b.X)? a.X<b.X : a.Y<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(norm(b) < norm(c)) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSP(const L& s, const P& p){
    return abs(s[0]-p) +abs(s[1]-p) -abs(s[1]-s[0]) < EPS;
}
bool intersectSS(const L& s, const L& t){
    for(int i=0; i<2; i++){
        for(int j=0; j<2; j++){
            if(s[i]==t[j]) return true;
        }
    }
    return ( ccw(s[0],s[1],t[0]) *ccw(s[0],s[1],t[1]) <= 0 ) &&
        ( ccw(t[0],t[1],s[0]) *ccw(t[0],t[1],s[1]) <= 0 );
}

P projection(const L& l, const P& p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L& l, const P& p) {
  return p + 2.0*(projection(l, p) -p);
}

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

bool in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int cn=0;
    for(int i=0; i<n; i++){
        if(intersectSP(L(poly[i], poly[(i+1)%n]), p)){
            return true;
        }
    }
    L ray(p, p+P(INF, 0));
    for(int i=0; i<n; i++){
        if((poly[i].Y <= p.Y && poly[(i+1)%n].Y > p.Y) ||
           (poly[i].Y > p.Y && poly[(i+1)%n].Y <= p.Y)){
            if(intersectSS(ray, L(poly[i],poly[(i+1)%n]))){
                cn++;
            }
        }
    }
    return cn%2 != 0;
}

bool isVisible(const L &l, const vector<VP> &poly){
	VP cp;
	for(int r=0; r<(int)poly.size(); r++){
    	int n = poly[r].size();
    	for(int i=0; i<n; i++){
    	    L edge(poly[r][i], poly[r][(i+1)%n]);
    	    if(!isParallel(l, edge) && intersectSS(l, edge)){
    	        cp.push_back(crosspointLL(l, edge));
    	    }
    	}
    }
    sort(cp.begin(), cp.end());
    cp.erase(unique(cp.begin(), cp.end()), cp.end());
    
    bool ret = true;
    for(int r=0; r<(int)poly.size() && ret ; r++){
    	for(int i=0; i<(int)cp.size()-1; i++){
    	    if(!in_poly((cp[i]+cp[i+1])/2.0, poly[r])){
    	        ret = false;
    	        break;
    	    }
    	}
    }
    return ret;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;
        
        vector<VP> building(n);
        for(int i=0; i<n; i++){
        	int m;
        	cin >> m;
        	building[i].resize(m);
        	for(int j=0; j<m; j++){
        		int x,y;
        		cin >> x >> y;
        		building[i][j] = P(x,y);
        	}
        }
        int sx,sy, gx,gy;
        int lx1, ly1, lx2, ly2;
        cin >>sx>>sy>>gx>>gy>>lx1>>ly1>>lx2>>ly2;
        P s(sx, sy), g(gx, gy);
        L axis(P(lx1, ly1), P(lx2, ly2));
        if(ccw(axis[0], axis[1], s) < 0) swap(axis[0], axis[1]);
        
        vector<VP> poly(2);
        for(int i=0; i<n; i++){
        	if(ccw(axis[0], axis[1], building[i][0]) > 0){
        		if(in_poly(s, building[i])){
        			poly[0] = building[i];
        		}
        	}else{
        		if(in_poly(reflection(axis, s), building[i])){
        			if(in_poly(reflection(axis, g), building[i])){
        				poly[1] = building[i];
        			}else{
        				break;
        			}
        		}
        	}
        }
        if(poly[1].empty()){
        	cout << "impossible" << endl;
        	continue;
        }
        
        reverse(poly[1].begin(), poly[1].end());
        for(int i=0; i<(int)poly[1].size(); i++){
        	poly[1][i] = reflection(axis, poly[1][i]);
        }
        VP cp;
        cp.reserve(102);
        cp.push_back(s);
        cp.push_back(g);
        for(int r=0; r<2; r++){
        	for(int i=0; i<(int)poly[r].size(); i++){
        		if(in_poly(poly[r][i], poly[1-r])){
        			cp.push_back(poly[r][i]);
        		}
        	}
        }
        
        int sc = cp.size();
        vector<vector<pair<int, double> > > adj(sc);
        for(int i=0; i<sc; i++){
        	for(int j=i+1; j<sc; j++){
        		if(isVisible(L(cp[i], cp[j]), poly)){
        			double d = abs(cp[i]-cp[j]);
        			adj[i].push_back(make_pair(j,d));
        			adj[j].push_back(make_pair(i,d));
        		}
        	}
        }
        
        priority_queue<pair<double, int> > wait;
        vector<double> mincost(sc, INF);
        wait.push(make_pair(0, 0));
        mincost[0] = 0;
        while(!wait.empty()){
        	int idx = wait.top().second;
        	double cost = -wait.top().first;
        	wait.pop();
        	if(cost > mincost[idx]+EPS) continue;
        	if(idx == 1) break;
        	for(int i=0; i<(int)adj[idx].size(); i++){
        		int nidx = adj[idx][i].first;
        		double ncost = adj[idx][i].second;
        		if(cost +ncost +EPS < mincost[nidx]){
        			wait.push(make_pair(-(cost+ncost), nidx));
        			mincost[nidx] = cost +ncost;
        		}
        	}
        }
        if(mincost[1]==INF){
        	cout << "impossible" << endl;
        }else{
        	cout << fixed;
        	cout << setprecision(10);
        	cout << mincost[1] << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 400
memory_kb: 3364
final_rank: 14

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

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

namespace std{
	bool operator < (const P &a, const P &b){
		return (a.X!=b.X)? a.X<b.X : a.Y<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(norm(b) < norm(c)) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSP(const L& s, const P& p){
    return abs(s[0]-p) +abs(s[1]-p) -abs(s[1]-s[0]) < EPS;
}
bool intersectSS(const L& s, const L& t){
    for(int i=0; i<2; i++){
        for(int j=0; j<2; j++){
            if(s[i]==t[j]) return true;
        }
    }
    return ( ccw(s[0],s[1],t[0]) *ccw(s[0],s[1],t[1]) <= 0 ) &&
        ( ccw(t[0],t[1],s[0]) *ccw(t[0],t[1],s[1]) <= 0 );
}

P projection(const L& l, const P& p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L& l, const P& p) {
  return p + 2.0*(projection(l, p) -p);
}

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

bool in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int cn=0;
    for(int i=0; i<n; i++){
        if(intersectSP(L(poly[i], poly[(i+1)%n]), p)){
            return true;
        }
    }
    L ray(p, p+P(INF, 0));
    for(int i=0; i<n; i++){
        if((poly[i].Y <= p.Y && poly[(i+1)%n].Y > p.Y) ||
           (poly[i].Y > p.Y && poly[(i+1)%n].Y <= p.Y)){
            if(intersectSS(ray, L(poly[i],poly[(i+1)%n]))){
                cn++;
            }
        }
    }
    return cn%2 != 0;
}

bool isVisible(const L &l, const vector<VP> &poly){
	VP cp;
	for(int r=0; r<(int)poly.size(); r++){
    	int n = poly[r].size();
    	for(int i=0; i<n; i++){
    	    L edge(poly[r][i], poly[r][(i+1)%n]);
    	    if(!isParallel(l, edge) && intersectSS(l, edge)){
    	        cp.push_back(crosspointLL(l, edge));
    	    }
    	}
    }
    sort(cp.begin(), cp.end());
    cp.erase(unique(cp.begin(), cp.end()), cp.end());
    
    bool ret = true;
    for(int r=0; r<(int)poly.size() && ret ; r++){
    	for(int i=0; i<(int)cp.size()-1; i++){
    	    if(!in_poly((cp[i]+cp[i+1])/2.0, poly[r])){
    	        ret = false;
    	        break;
    	    }
    	}
    }
    return ret;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;
        
        vector<VP> building(n);
        for(int i=0; i<n; i++){
        	int m;
        	cin >> m;
        	building[i].resize(m);
        	for(int j=0; j<m; j++){
        		int x,y;
        		cin >> x >> y;
        		building[i][j] = P(x,y);
        	}
        }
        int sx,sy, gx,gy;
        int lx1, ly1, lx2, ly2;
        cin >>sx>>sy>>gx>>gy>>lx1>>ly1>>lx2>>ly2;
        P s(sx, sy), g(gx, gy);
        L axis(P(lx1, ly1), P(lx2, ly2));
        if(ccw(axis[0], axis[1], s) < 0) swap(axis[0], axis[1]);
        
        vector<VP> poly(2);
        for(int i=0; i<n; i++){
        	if(ccw(axis[0], axis[1], building[i][0]) > 0){
        		if(in_poly(s, building[i])){
        			poly[0] = building[i];
        		}
        	}else{
        		if(in_poly(reflection(axis, s), building[i])){
        			if(in_poly(reflection(axis, g), building[i])){
        				poly[1] = building[i];
        			}else{
        				break;
        			}
        		}
        	}
        }
        if(poly[1].empty()){
        	cout << "impossible" << endl;
        	continue;
        }
        
        reverse(poly[1].begin(), poly[1].end());
        for(int i=0; i<(int)poly[1].size(); i++){
        	poly[1][i] = reflection(axis, poly[1][i]);
        }
        VP cp;
        cp.reserve(102);
        cp.push_back(s);
        cp.push_back(g);
        for(int r=0; r<2; r++){
        	for(int i=0; i<(int)poly[r].size(); i++){
        		if(in_poly(poly[r][i], poly[1-r])){
        			cp.push_back(poly[r][i]);
        		}
        	}
        }
        
        int sc = cp.size();
        vector<vector<double> > adj(sc, vector<double>(sc, INF));;
        for(int i=0; i<sc; i++){
        	for(int j=i+1; j<sc; j++){
        		if(isVisible(L(cp[i], cp[j]), poly)){
        			adj[i][j] = adj[j][i] = abs(cp[i]-cp[j]);
        		}
        	}
        }
        for(int k=0; k<sc; k++){
        	for(int i=0; i<sc; i++){
        		for(int j=0; j<sc; j++){
        			adj[i][j] = min(adj[i][j], adj[i][k]+adj[k][j]);
        		}
        	}
        }
        if(adj[0][1] == INF){
        	cout << "impossible" << endl;
        }else{
        	cout << fixed;
        	cout << setprecision(10);
        	cout << adj[0][1] << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 420
memory_kb: 3408
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef complex<double> P;
typedef complex<double> V;
typedef vector<P> vecP;
typedef pair<P,P> L;
typedef pair<P,P> S;

const double eps=1e-5;
const double PI=acos(-1);
const double PI2=PI*2.0;
 
namespace std{
  bool operator < (const P &a,const P &b){
    return (a.real()!=b.real()?
            a.real() <b.real():
            a.imag() <b.imag());
  }
};
 
V normal(V a){
  assert( abs(a)>0 );
  return a/abs(a);
}
 
double Sqrt( double x ){
  if(x<0)return 0;
  else return sqrt(x);
}
 
P Vector(L a){
  return a.second-a.first;
}
 
bool eq(double a,double b){
  double ep = max( eps, max(abs(a),abs(b))*eps );
  return (-ep< a-b && a-b <ep);
}
 
bool eq(P a,P b){
  return ( eq(a.real(),b.real()) && eq(a.imag(),b.imag()) );
}
 
double dot(P a,P b){
  return real(b*conj(a));
}
 
double cross(P a,P b){
  return imag(b*conj(a));
}
 
double getArg(P a,P b){
  return arg(b*conj(a));
}
 
double getTime(V a,V b){
  assert( eq(cross(a,b),0) );
  return ( dot(a,b) < 0 ? -1.0 : 1.0 ) * abs(b) / abs(a);
}
 
P project(P a,P b,P c){
  b-=a,c-=a;
  return a+b*real(c/b);
}
 
P reflect(P a,P b,P c){
  b-=a,c-=a;
  return a+b*conj(c/b);
}
P reflect(S s,P p){
  return reflect( s.first, s.second, p );
  
}
 
int ccw(P a,P b,P c){
  P ab=b-a,ac=c-a;
  P k=ac*conj(ab);
  if(k.imag()>eps)return 1;
  if(k.imag()<-eps)return -1;
  if(k.real()<-eps)return 2;
  if(abs(ab)+eps<abs(ac))return -2;
  return 0;
}
 
bool isParallel(P a,P b){
  return eq(0, cross(a,b));
}
 
bool isParallel(S a,S b){
  return eq(0, cross( Vector(a) , Vector(b) ) );
}
 
bool onLP(L l,P p){
  P a=l.first, b=l.second;
  return eq(0, cross(b-a,p-a));
}
 
bool onSP(S s,P p){
  P a=s.first, b=s.second;
  return eq( abs(b-a) , abs(a-p)+abs(b-p) );
}
 
bool isCrossSS(S s0,S s1){
  P a=s0.first, b=s0.second;
  P c=s1.first, d=s1.second;
  int f0 = ccw(a,b,c) * ccw(a,b,d);
  int f1 = ccw(c,d,a) * ccw(c,d,b);
  return (f0<=0 && f1<=0);
}
 
bool isCrossLS(L l,S s){
  P a=l.first, b=l.second;
  P c=s.first, d=s.second;
  return ( ccw(a,b,c) * ccw(a,b,d) <= 0 );
}
 
double distLP(L l,P p){
  P a=l.first, b=l.second;
  double res = cross(b-a,p-a) / abs(b-a);
  return abs(res);
}
 
double distSP(S s,P p){
  P a=s.first, b=s.second;
  if( dot(b-a,p-a) < eps )return abs(p-a);
  if( dot(a-b,p-b) < eps )return abs(p-b);
  return distLP(s,p);
}
 
double distSS(S s0,S s1){
  if( isCrossSS(s0,s1) )return 0;
  double res0 = min( distSP( s0, s1.first ) , distSP(s0, s1.second) );
  double res1 = min( distSP( s1, s0.first ) , distSP(s1, s0.second) );
  return min(res0,res1);
}
 
P getCrossLL(L l0,L l1){
  P a=l0.first, b=l0.second;
  P c=l1.first, d=l1.second;
  a-=d;b-=d;c-=d;
  return d+a+(b-a)*imag(a/c)/imag(a/c-b/c);
}
  
P getVector(const vecP &t, int id){
  int n=t.size();
  return t[ (id+1)%n ] - t[id%n];
}

void pr(P p,string str="\n"){
  printf("%.10f %.10f",p.real(),p.imag());
  cout<<str;
}

int checkPolygonP(vecP &t, P p){
  int n=t.size();
  double sum=0;
  for(int i=0;i<n;i++){
    P a=t[i], b=t[(i+1==n?0:i+1)];
    if( ccw(a,b,p)==0 ){
      return 1;
    }
    sum+= getArg(a-p,b-p);
  }
  if( abs(sum) < eps )return 0;
  return 2;
}


void checkPolygonS(vecP &t,S s,int &maxm,int &mini){
  int n=t.size();

  typedef pair< double , int > Pair;
  
  vector< P > u;
  vector< Pair > v;
  for(int i=0;i<n;i++){
    P a=t[i], b=t[(i+1==n?0:i+1)];
    S base=S(a,b);
    if( isParallel(base,s) )continue;
    if( !isCrossSS(base,s) )continue;
    
    P target=getCrossLL( base, s );

    if( !onLP( s, target ) ){
           cout<<s.first<<' '<<s.second<<endl;
           cout<<base.first<<' '<<base.second<<endl;
           cout<<target<<endl;
      continue;
    }

    
    Pair pair;
    pair.first=getTime( s.second-s.first, target-s.first );
    pair.second=u.size();
    u.push_back(target);
    v.push_back( pair );
  }
  
  v.push_back( Pair(0.0,u.size()) );
  u.push_back( s.first );
  v.push_back( Pair(1.0,u.size()) );
  u.push_back( s.second );
  sort(v.begin(),v.end());

  maxm=-1;
  mini=3;
  for(int i=0;i<(int)v.size();i++){
    int f=checkPolygonP(t,u[v[i].second]);
    maxm=max(maxm,f);
    mini=min(mini,f);
    if(i+1<(int)v.size()){
      int h=checkPolygonP(t, (u[v[i].second]+u[v[i+1].second])*0.5 );
      maxm=max(maxm,h);
      mini=min(mini,h);
    }
  }

}

bool inPolygonS(vecP &t,S s){
  int maxm,mini;
  checkPolygonS(t,s,maxm,mini);
  if(mini==0)return false;
  return true;
}

bool outPolygonS(vecP &t,S s){
  int maxm,mini;
  checkPolygonS(t,s,maxm,mini);
  if(maxm==2)return false;
  return true;
}

void pr(P p){
  printf("%.3f %.3f\n",p.real(),p.imag());
}

////////////////

struct state{
  double cost;
  int pos;
  state(double x,int y):cost(x),pos(y) {}
  bool operator < (const state &s)const{
    return cost > s.cost;
  }
};

P input(){
  double x,y;
  cin>>x>>y;
  return P(x,y);
}

S getS(vecP &t,int index){
  int n=t.size();
  index%=n;
  return S(t[index], t[ (index+1)%n ]);
}

double solve(vector< vecP > &a, P si, P ti, L line ){
  vecP A,B;
  for(int i=0;i<(int)a.size();i++){
    if( checkPolygonP(a[i],si) > 0 &&
        checkPolygonP(a[i],ti) > 0 ){
      A=a[i];
    }
    if( checkPolygonP(a[i], reflect(line,si) ) > 0 &&
        checkPolygonP(a[i], reflect(line,ti) ) > 0){
      B=a[i];
    }
  }
  if(A.empty() || B.empty())return -1;
  for(int i=0;i<(int)B.size();i++)B[i]=reflect(line,B[i]);
  vecP t;
  for(int i=0;i<(int)A.size();i++)t.push_back(A[i]);
  for(int i=0;i<(int)B.size();i++)t.push_back(B[i]);
  for(int i=0;i<(int)A.size();i++){
    for(int j=0;j<(int)B.size();j++){
      S fi=getS(A,i);
      S se=getS(B,j);
      if( !isParallel(fi,se) && isCrossSS(fi,se) ){
        t.push_back( getCrossLL(fi,se) );
      }
    }
  }
  
  t.push_back( si );
  t.push_back( ti );
  sort(t.begin(),t.end());
  t.erase( unique(t.begin(),t.end()), t.end() );
  
  vector<double> d( t.size(), 1e9);
  int sid = lower_bound( t.begin(), t.end(), si ) - t.begin();
  int tid = lower_bound( t.begin(), t.end(), ti ) - t.begin();
  
  d[ sid ]=0;
  priority_queue< state > Q;
  Q.push( state( 0, sid ) );
  while(!Q.empty()){
    state s=Q.top();Q.pop();

    if(s.pos==tid)return s.cost;
    
    if( d[s.pos] < s.cost )continue;
    for(int to=0;to<(int)t.size();to++){
      if( s.pos == to )continue;
      S path = S( t[s.pos] , t[to] );
      if(!inPolygonS(A,path))continue;
      if(!inPolygonS(B,path))continue;
      double ncost = s.cost + abs( path.second-path.first );
      if( d[to] - eps > ncost ){
        d[to] = ncost;
        Q.push( state(ncost,to) );
      }
    }
  }

  return -1;
}

int main(){
  int n;

  while(cin>>n&&n){
    //    cout<<n<<" ";
    vector< vecP > a;
    a.resize(n);
    for(int i=0;i<n;i++){
      int m;
      cin>>m;
      //      cout<<m<<" ";
      a[i].resize(m);
      for(int j=0;j<m;j++){
        a[i][j]=input();
      }
    }


    P si=input();
    P ti=input();
    
    L line;
    line.first=input();
    line.second=input();

    double ans = solve( a, si, ti ,line );


    if( n==2&& (int)a[0].size()==50 && (int)a[1].size()==4){
      //      cout<<n<<' '<<a[0].size()<<' '<<a[1].size()<<endl;
      /*

      cout<<n<<endl;
      for(int i=0;i<n;i++){
        cout<<a[i].size()<<endl;
        for(int j=0;j<(int)a[i].size();j++){
          cout<<a[i][j].real()<<' '<<a[i][j].imag()<<endl;
        }
      }
        cout<<si.real()<<' '<<si.imag()<<endl;
        cout<<ti.real()<<' '<<ti.imag()<<endl;
        cout<< line.first.real()<<' '<<line.first.imag()<<endl;
        cout<< line.second.real()<<' '<<line.second.imag()<<endl;
      */

    }

    if(ans < 0){
            printf("impossible\n");
    }else{
            printf("%.10f\n",ans);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 1820
memory_kb: 3500
final_rank: 18

code_snippet: #include<bits/stdc++.h>
#define MAX 200
#define inf 1<<29
#define linf 1e18
#define eps (1e-8)
#define mod 1000000007
#define pi M_PI
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<double,int> pdi;
typedef vector<int> vi;
typedef vector<pii> vpi;
const int dx[8]={1,0,-1,0,1,1,-1,-1};
const int dy[8]={0,1,0,-1,1,-1,1,-1};

class Point{
public:
  double x,y;
  Point(double x=0,double y=0):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 k){ return Point(x*k,y*k);}
  Point operator/(double k){ return Point(x/k,y/k);}
  bool operator<(Point p)const{ return (x!=p.x ? x<p.x : y<p.y);}
  bool operator==(Point p)const{ return fabs(x-p.x)<eps && fabs(y-p.y)<eps;}

  double abs(){ return sqrt(norm());}
  double norm(){ return (x*x+y*y);}
};
typedef Point Vector;
typedef vector<Point> Polygon;

class Segment{
public:
  Point p1,p2;
  Segment(Point p1=Point(),Point p2=Point()):p1(p1),p2(p2){}
  bool operator==(Segment s){ 
    if(p1==s.p1 && p2==s.p2)return true;
    if(p1==s.p2 && p2==s.p1)return true;
    return false;
  }
};
typedef Segment Line;

double norm(Vector a){ return (a.x*a.x+a.y*a.y);}
double abs(Vector a){ return sqrt(norm(a));}
double dot(Vector a,Vector b){ return (a.x*b.x+a.y*b.y);}
double cross(Vector a,Vector b){ return (a.x*b.y-a.y*b.x);}

bool isParallel(Vector a,Vector b){
  return equals(cross(a,b),0.0);
}

bool isParallel(Segment s,Segment t){
  return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0);
}

Point project(Segment s,Point p){
  Vector base=(s.p2-s.p1);
  double r=(dot(p-s.p1,base)/base.norm());
  return (s.p1+base*r);
}

Point reflect(Segment s,Point p){
  return p+(project(s,p)-p)*2;
}

int ccw(Point p0,Point p1,Point p2){
  Vector a=p1-p0;
  Vector b=p2-p0;
  if(cross(a,b)>eps)return 1;
  if(cross(a,b)<-eps)return -1;
  if(dot(a,b)<-eps)return 2;
  if(a.norm()<b.norm())return -2;
  return 0;
}

bool intersect(Point p1,Point p2,Point p3,Point p4){
  return (ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0 &&
          ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}

bool intersect(Segment s1,Segment s2){
  return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}

Point getCrossPointLL(Line a,Line b){
  double A=cross(a.p2-a.p1,b.p2-b.p1);
  double B=cross(a.p2-a.p1,a.p2-b.p1);
  if(abs(A)<eps || abs(B)<eps)return b.p1;
  return b.p1+(b.p2-b.p1)*(B/A);
}

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

Polygon reflect(Polygon p,Line L){
  Polygon res;
  for(int i=0;i<p.size();i++)res.push_back(reflect(L,p[i]));
  reverse(res.begin(),res.end());
  return res;
}

vector<Point> unique(vector<Point> vp){
  sort(vp.begin(),vp.end());
  vector<Point> res;
  res.push_back(vp[0]);
  for(int i=1;i<vp.size();i++){
    if(!(vp[i]==res.back()))res.push_back(vp[i]);
  }
  return res;
}

int n;
Polygon buildings[100];
Point s,t,rs,rt;
Line L;
vector<pdi> e[MAX];
Polygon p1,p2;
vector<Point> vp;

void init(){
  FOR(i,0,n)buildings[i].clear();
  vp.clear();
  p1.clear();
  p2.clear();
  FOR(i,0,MAX)e[i].clear();
}

void add_edge(int from,int to,double cost){
  e[from].pb(mp(cost,to));
  e[to].pb(mp(cost,from));
}

bool check(Point a,Point b){
  Segment s1=Segment(a,b);
  FOR(i,0,p1.size()){
    Segment s2=Segment(p1[i],p1[(i+1)%p1.size()]);
    if(isParallel(s1,s2))continue;
    if(intersect(s1,s2)){
      Point c=getCrossPointLL(s1,s2);
      if(!(c==a) && !(c==b))return false;
    }
  }
  FOR(i,0,p2.size()){
    Segment s2=Segment(p2[i],p2[(i+1)%p2.size()]);
    if(isParallel(s1,s2))continue;
    if(intersect(s1,s2)){
      Point c=getCrossPointLL(s1,s2);
      if(!(c==a) && !(c==b))return false;
    }
  }
  Point m=a+(b-a)/2;
  if(contains(p1,m)==0)return false;
  if(contains(p2,m)==0)return false;
  return true;
}

double dijkstra(int s,int t){
  double d[MAX];
  fill(d,d+MAX,inf);
  priority_queue<pdi,vector<pdi>,greater<pdi> > pq;
  pq.push(mp(0,s));
  d[s]=0;

  while(pq.size()){
    pdi u=pq.top();
    pq.pop();
    if(d[u.s]<u.f)continue;
    if(u.s==t)return u.f;

    FOR(i,0,e[u.s].size()){
      pdi next=e[u.s][i];
      if(d[u.s]+next.f<d[next.s]){
        d[next.s]=d[u.s]+next.f;
        pq.push(mp(d[next.s],next.s));
      }
    }
  }
  return -1;
}

double solve(){
  rs=reflect(L,s);
  rt=reflect(L,t);
  FOR(i,0,n){
    if(contains(buildings[i],s)!=0 &&
       contains(buildings[i],t)!=0 )p1=buildings[i];
    if(contains(buildings[i],rs)!=0 && 
       contains(buildings[i],rt)!=0 )p2=buildings[i];
  }
  if(p2.size()==0)return -1;
  p2=reflect(p2,L);
  FOR(i,0,p1.size())vp.pb(p1[i]);
  FOR(i,0,p2.size())if(contains(p1,p2[i])!=0)vp.pb(p2[i]);
  vp=unique(vp);
  vp.pb(s);
  vp.pb(t);
  FOR(i,0,vp.size()){
    FOR(j,i+1,vp.size()){
      if(check(vp[i],vp[j]))add_edge(i,j,abs(vp[i]-vp[j]));
    }
  }
  return dijkstra(vp.size()-2,vp.size()-1);
}

int main()
{
  while(1){
    cin>>n;
    if(n==0)break;
    init();
    FOR(i,0,n){
      int m;
      Polygon p;
      cin>>m;
      FOR(j,0,m){
        int x,y;
        cin>>x>>y;
        p.pb(Point(x,y));
      }
      buildings[i]=p;
    }
    cin>>s.x>>s.y>>t.x>>t.y;
    cin>>L.p1.x>>L.p1.y>>L.p2.x>>L.p2.y;
    double ans=solve();
    if(ans==-1)cout<<"impossible"<<endl;
    else pd(ans);
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3280
final_rank: 9

code_snippet: #include <bits/stdc++.h>
 
using namespace std;
 
#define EPS 1e-8
#define equal(a,b) (fabs(a-b) < EPS)
#define lt(a,b) (a-b < -EPS)
#define MAX_N 100
#define MAX_P 500
#define INF 1e9
 
struct Point{
    double x,y;
 
    Point(){}
    Point(double x,double y) : x(x),y(y) {}
 
    Point operator + (const Point &p)const{ return Point(x+p.x,y+p.y); }
    Point operator - (const Point &p)const{ return Point(x-p.x,y-p.y); }
    Point operator * (const double &k)const{ return Point(x*k,y*k); }
    Point operator / (const double &k)const{ return Point(x/k,y/k); }
    bool operator < (const Point &p)const{
	if(!equal(x,p.x)){
	    return lt(x,p.x);
	}else{
	    return lt(y,p.y);
	}
    }
    bool operator == (Point &p)const{
	if(equal(x,p.x) && equal(y,p.y)){
	    return true;
	}
	return false;
    }
};
 
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 - b.x*a.y; }
double norm(const Point &p){ return dot(p,p); }
double abs(const Point &p){ return sqrt(norm(p)); }
double dist(const Point &a,const Point &b){
    return sqrt(pow(a.x-b.x,2) + pow(a.y-b.y,2));
}
 
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
typedef Point Vector;
 
int ccw(const Point &p0,const Point &p1,const Point &p2){
    Vector a = p1 - p0;
    Vector 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;
}
 
typedef Point Vector;
 
struct Segment{
    Point s,t;
    Segment(){}
    Segment(Point s,Point t) : s(s),t(t) {}
    bool operator == (Segment &seg)const{
	if(s == seg.s && t == seg.t){
	    return true;
	}
	if(t == seg.s && s == seg.t){
	    return true;
	}
	return false;
    }
};
 
bool isIntersectSS(const Segment &a,const Segment &b){
    Point s[2] = {a.s,a.t}, t[2] = {b.s,b.t};
    return (ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0
	    && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0);
}
 
Point crosspointSS(const Segment &a,const Segment &b){
    Vector va = a.t-a.s, vb = b.t-b.s;
    double d = cross(vb,va);
    return a.s+va*cross(vb,b.t-a.s)*(1.0/d);
}
 
struct Line{
    Point s,t;
    Line(){}
    Line(Point s,Point t) : s(s),t(t) {}
};
 
Point projection(const Line &l,const Point &p){
    Vector b = l.t-l.s;
    double t = dot(p-l.s,b)/norm(b);
    return l.s+b*t;
}
 
Point reflection(const Line &l,const Point &p){
    return p+(projection(l,p)-p)*2.0;
}
 
#define curr(G,i) (G[i%G.size()])
#define next(G,i) (G[(i+1)%G.size()])
typedef vector<Point> Polygon;
 
int containPP(const Polygon &pg,const Point &p){
    int N = pg.size();
    bool in = false;
    for(int i = 0 ; i < N ; i++){
	Point a = curr(pg,i)-p, b = next(pg,i)-p;
	if(a.y > b.y){ swap(a,b); }
	if(a.y <= 0 && 0 < b.y && cross(a,b) < 0){ in = !in; }
	if(cross(a,b) == 0 && dot(a,b) <= 0){ return 1; }
    }
    return (in ? 2 : 0);
}
 
struct Data{
    Point p;
    double d;
    Data(Point p,double d) : p(p),d(d) {}
    bool operator < (const Data &data)const{
	if(!equal(d,data.d)){
	    return lt(d,data.d);
	}else{
	    return p < data.p;
	}
    }
};
 
bool containPS(const Polygon &pg,Segment &s){
    vector<Data> v;
    v.push_back(Data(s.s,0));
    v.push_back(Data(s.t,dist(s.s,s.t)));
    set<Point> st;
    for(int i = 0 ; i < (int)pg.size() ; i++){
	Segment seg(curr(pg,i),next(pg,i));
	if(seg == s) return true;
	if(ccw(seg.s,seg.t,s.s) == 0 && ccw(seg.s,seg.t,s.t) == 0){
	    return true;
	}
 
	if(isIntersectSS(s,seg)){
	    Point cp = crosspointSS(s,seg);
	    double d = dist(cp,s.s);
	    if(st.find(cp) != st.end()){
		continue;
	    }
	    st.insert(cp);
	    v.push_back(Data(cp,d));
	}
    }
    sort(v.begin(),v.end());
    for(int i = 0 ; i < (int)v.size()-1 ; i++){
	Point cp = (v[i].p + v[i+1].p) / 2.0;
	if(containPP(pg,cp) == 0){
	    return false;
	}
    }
    return true;
}
 
struct Edge{
    int to;
    double cost;
    Edge(int to,double cost) : to(to),cost(cost) {}
};
 
struct State{
    int v;
    double d;
    State(int v,double d) : v(v),d(d) {}
    bool operator < (const State &s)const{
	return d > s.d;
    }
};
 
Polygon L,R;
vector<Edge> G[MAX_P];
 
double dijkstra(int s,int t){
    double dist[MAX_P];
    fill(dist,dist+MAX_P,INF);
    dist[s] = 0;
    priority_queue<State> Q;
    Q.push(State(s,0));
    while(!Q.empty()){
	State st = Q.top(); Q.pop();
	int v = st.v;
	if(lt(dist[v],st.d)){
	    continue;
	}
	if(v == t) return dist[t];
	for(int i = 0 ; i < (int)G[v].size() ; i++){
	    Edge e = G[v][i];
	    if(lt(dist[v]+e.cost,dist[e.to])){
		dist[e.to] = dist[v] + e.cost;
		Q.push(State(e.to,dist[e.to]));
	    }
	}
    }
    return INF;
}
 
void init(){
    for(int i = 0 ; i < MAX_P ; i++){
	G[i].clear();
    }
}
 
int main(){
    int N;
    while(cin >> N, N){
	init();
	Polygon b[MAX_N];
	for(int i = 0 ; i < N ; i++){
	    int M;
	    cin >> M; b[i].resize(M);
	    for(int j = 0 ; j < M ; j++){
		cin >> b[i][j].x >> b[i][j].y;
	    }
	}
	Point s,t;
	Line l;
	cin >> s.x >> s.y >> t.x >> t.y;
	cin >> l.s.x >> l.s.y >> l.t.x >> l.t.y;
	int n = -1;
	for(int i = 0 ; i < N ; i++){
	    if(containPP(b[i],s) != 0){
		n = i;
		L = b[n];
		break;
	    }
	}
	int rn = -1;
	Point rs = reflection(l,s);
	for(int i = 0 ; i < N ; i++){
	    if(containPP(b[i],rs) != 0){
		rn = i;
		R = b[rn];
		break;
	    }
	}
	Point rt = reflection(l,t);
	if(n == -1 || rn == -1 ||
	   containPP(R,rt) == 0){
	    cout << "impossible" << endl;
	    continue;
	}
 
	int size = L.size();
	int rsize = R.size();
	int src,dst;
	for(int i = 0 ; i < size ; i++){
	    L[i] = reflection(l,L[i]);
	}
	set<Point> st;
	for(int i = 0 ; i < size ; i++){
	    if(st.find(L[i]) == st.end()){
		st.insert(L[i]);
	    }
	}
 
	for(int i = 0 ; i < rsize ; i++){
	    if(st.find(R[i]) == st.end()){
		st.insert(R[i]);
	    }
	}
	s = reflection(l,s);
	t = reflection(l,t);
	if(st.find(s) == st.end()) st.insert(s);
	if(st.find(t) == st.end()) st.insert(t);
	vector<Point> vec;
	for(auto it = st.begin() ; it != st.end() ; ++it){
	    vec.push_back(*it);
	}
	size = vec.size();
	for(int i = 0 ; i < size ; i++){
	    for(int j = i+1 ; j < size ; j++){
		Segment seg(vec[i],vec[j]);
		if(containPS(L,seg) && containPS(R,seg)){
		    double d = dist(vec[i],vec[j]);
		    G[i].push_back(Edge(j,d));
		    G[j].push_back(Edge(i,d));
		}
	    }
	    if(s == vec[i]) src = i;
	    if(t == vec[i]) dst = i;
	}
	double res = dijkstra(src,dst);
	if(res == INF){
	    cout << "impossible" << endl;
	}else{
	    printf("%.10f\n",res);
	}
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 3348
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
typedef double D;
typedef complex<D> P;
typedef pair<P,P> L;
typedef vector<P> Pol;
D eps=1e-9,inf=1e9;
int A,n[100];
Pol pol[100];
P s,t;
L l;
bool eq(D a,D b){return abs(a-b)<eps;}
int sig(D a){return eq(a,0)?0:(a>0?1:-1);}
D cro(P a,P b){return imag(conj(a)*b);}
D dot(P a,P b){return real(conj(a)*b);}
int ccw(P a,P b,P c){
	if(sig(cro(b-a,c-a))==1) return 1;
	if(sig(cro(b-a,c-a))==-1) return -1;
	if(eq(abs(a-c)+abs(c-b),abs(a-b))) return 0;
	if(eq(abs(a-b)+abs(c-b),abs(a-c))) return -2;
	return 2;
}
int ccw(L a,P p){return ccw(a.fs,a.sc,p);}
P intLL(L a,L b){
	D t=cro(a.sc-a.fs,a.sc-b.fs)/cro(a.sc-a.fs,b.sc-b.fs);
	return b.fs+t*(b.sc-b.fs);
}
bool contain(Pol pol,P p){
	bool in=0;
	int N=pol.size();
	rep(i,N){
		P a=pol[i]-p,b=pol[(i+1)%N]-p;
		if(ccw(a,b,P(0,0))==0) return 1;
		if(imag(a)>imag(b)) swap(a,b);
		if(sig(imag(a))<=0&&0<sig(imag(b))&&ccw(P(0,0),a,b)==1) in=!in;
	}
	return in;
}
P perp(L l,P p){
	D t=dot(p-l.fs,l.fs-l.sc)/norm(l.fs-l.sc);
	return l.fs+t*(l.fs-l.sc);
}
P refl(L l,P p){
	return p+2.0*(perp(l,p)-p);
}
bool ispal(L a,L b){
	return sig(cro(a.fs-a.sc,b.fs-b.sc))==0;
}
bool iSS(L a,L b){
	return ccw(a,b.fs)*ccw(a,b.sc)<=0&&ccw(b,a.fs)*ccw(b,a.sc)<=0;
}
L BL;
bool compBL(const P& a,const P& b){			//BL?????????????????????(BL.fs??´????°???????)
	return dot(l.sc-l.fs,a-l.fs)<dot(l.sc-l.fs,b-l.fs);
}
bool containE(Pol pol,L l){
	vector<P> ps;
	ps.pb(l.fs);
	ps.pb(l.sc);
	int N=pol.size();
	rep(i,N){
		L a(pol[i],pol[(i+1)%N]);
		if(ispal(a,l)) continue;
		if(!ispal(a,l)&&iSS(a,l)) ps.pb(intLL(a,l));
	}
	BL=l;
	sort(all(ps),compBL);
	int K=ps.size();
	rep(i,K-1) ps.pb((ps[i]+ps[i+1])/2.0);
	for(P p:ps) if(!contain(pol,p)) return 0;
	return 1;
}
int main(){
	while(true){
		cin>>A;
		if(A==0) break;
		rep(i,A){
			pol[i].clear();
			cin>>n[i];
			rep(j,n[i]){
				int x,y;
				cin>>x>>y;
				pol[i].pb(P(x,y));
			}
		}
		{
			int a,b,c,d;
			cin>>a>>b>>c>>d;
			s=P(a,b),t=P(c,d);
			cin>>a>>b>>c>>d;
			l=L(P(a,b),P(c,d));
		}
		int a=-1,b=-1,c=-1,d=-1;
		rep(i,A){
			if(contain(pol[i],s)) a=i;
			if(contain(pol[i],t)) b=i;
			if(contain(pol[i],refl(l,s))) c=i;
			if(contain(pol[i],refl(l,t))) d=i;
		}
		if(a<0||b<0||c<0||d<0||a!=b||c!=d){
			puts("impossible");
			continue;
		}
		Pol e=pol[a],f=pol[c];
		int E=e.size(),F=f.size();
		rep(i,F/2) swap(f[i],f[F-1-i]);
		rep(i,F) f[i]=refl(l,f[i]);
		Pol ps;
		ps.pb(s);
		ps.pb(t);
		for(P p:e) ps.pb(p);
		for(P p:f) ps.pb(p);
		int N=ps.size();
		D dis[102][102]={};
		rep(i,N) rep(j,N) if(i!=j){
			dis[i][j]=inf;
			if(containE(e,L(ps[i],ps[j]))&&containE(f,L(ps[i],ps[j]))) dis[i][j]=abs(ps[i]-ps[j]);
		}
		rep(i,N) rep(j,N) rep(k,N) chmin(dis[j][k],dis[j][i]+dis[i][k]);
		if(dis[0][1]==inf) puts("impossible");
		else printf("%.12f\n",dis[0][1]);
	}
}
accuracy: 1
time_ms: 510
memory_kb: 3312
final_rank: 17

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define EPS 1e-8
#define equal(a,b) (fabs(a-b) < EPS)
#define lt(a,b) (a-b < -EPS)
#define MAX_N 100
#define MAX_P 500
#define INF 1e9

struct Point{
  double x,y;

  Point(){}
  Point(double x,double y) : x(x),y(y) {}

  Point operator + (const Point &p)const{ return Point(x+p.x,y+p.y); }
  Point operator - (const Point &p)const{ return Point(x-p.x,y-p.y); }
  Point operator * (const double &k)const{ return Point(x*k,y*k); }
  Point operator / (const double &k)const{ return Point(x/k,y/k); }
  bool operator < (const Point &p)const{
    if(!equal(x,p.x)){
      return lt(x,p.x);
    }else{
      return lt(y,p.y);
    }
  }
  bool operator == (Point &p)const{
    if(equal(x,p.x) && equal(y,p.y)){
      return true;
    }
    return false;
  }
};

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 - b.x*a.y; }
double norm(const Point &p){ return dot(p,p); }
double abs(const Point &p){ return sqrt(norm(p)); }
double dist(const Point &a,const Point &b){
  return sqrt(pow(a.x-b.x,2) + pow(a.y-b.y,2));
}

#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0
typedef Point Vector;

int ccw(const Point &p0,const Point &p1,const Point &p2){
  Vector a = p1 - p0;
  Vector 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;
}

typedef Point Vector;

struct Segment{
  Point s,t;
  Segment(){}
  Segment(Point s,Point t) : s(s),t(t) {}
  bool operator == (Segment &seg)const{
    if(s == seg.s && t == seg.t){
      return true;
    }
    if(t == seg.s && s == seg.t){
      return true;
    }
    return false;
  }
};

bool isIntersectSS(const Segment &a,const Segment &b){
  Point s[2] = {a.s,a.t}, t[2] = {b.s,b.t};
  return (ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0
          && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0);
}

Point crosspointSS(const Segment &a,const Segment &b){
  Vector va = a.t-a.s, vb = b.t-b.s;
  double d = cross(vb,va);
  return a.s+va*cross(vb,b.t-a.s)*(1.0/d);
}

struct Line{
  Point s,t;
  Line(){}
  Line(Point s,Point t) : s(s),t(t) {}
};

Point projection(const Line &l,const Point &p){
  Vector b = l.t-l.s;
  double t = dot(p-l.s,b)/norm(b);
  return l.s+b*t;
}

Point reflection(const Line &l,const Point &p){
  return p+(projection(l,p)-p)*2.0;
}

#define curr(G,i) (G[i%G.size()])
#define next(G,i) (G[(i+1)%G.size()])
typedef vector<Point> Polygon;

int containPP(const Polygon &pg,const Point &p){
  int N = pg.size();
  bool in = false;
  for(int i = 0 ; i < N ; i++){
    Point a = curr(pg,i)-p, b = next(pg,i)-p;
    if(a.y > b.y){ swap(a,b); }
    if(a.y <= 0 && 0 < b.y && cross(a,b) < 0){ in = !in; }
    if(cross(a,b) == 0 && dot(a,b) <= 0){ return 1; }
  }
  return (in ? 2 : 0);
}

struct Data{
  Point p;
  double d;
  Data(Point p,double d) : p(p),d(d) {}
  bool operator < (const Data &data)const{
    if(!equal(d,data.d)){
      return lt(d,data.d);
    }else{
      return p < data.p;
    }
  }
};

bool containPS(const Polygon &pg,Segment &s){
  vector<Data> v;
  v.push_back(Data(s.s,0));
  v.push_back(Data(s.t,dist(s.s,s.t)));
  set<Point> st;
  for(int i = 0 ; i < (int)pg.size() ; i++){
    Segment seg(curr(pg,i),next(pg,i));
    if(seg == s){ return true; }
    if(ccw(seg.s,seg.t,s.s) == 0 && ccw(seg.s,seg.t,s.t) == 0){
      return true;
    }

    if(isIntersectSS(s,seg)){
      Point cp = crosspointSS(s,seg);
      double d = dist(cp,s.s);
      if(st.find(cp) != st.end()){
        continue;
      }
      st.insert(cp);
      v.push_back(Data(cp,d));
    }
  }
  sort(v.begin(),v.end());
  for(int i = 0 ; i < (int)v.size()-1 ; i++){
    Point cp = (v[i].p + v[i+1].p) / 2.0;
    if(containPP(pg,cp) == 0){
      return false;
    }
  }
  return true;
}

struct Edge{
  int to;
  double cost;
  Edge(int to,double cost) : to(to),cost(cost) {}
};

struct State{
  int v;
  double d;
  State(int v,double d) : v(v),d(d) {}
  bool operator < (const State &s)const{
    return d > s.d;
  }
};

Polygon L,R;
vector<Edge> G[MAX_P];

double dijkstra(int s,int t){
  double dist[MAX_P];
  fill(dist,dist+MAX_P,INF);
  dist[s] = 0;
  priority_queue<State> Q;
  Q.push(State(s,0));
  while(!Q.empty()){
    State st = Q.top(); Q.pop();
    int v = st.v;
    if(lt(dist[v],st.d)){
      continue;
    }
    if(v == t){ return dist[t]; }
    for(int i = 0 ; i < (int)G[v].size() ; i++){
      Edge e = G[v][i];
      if(lt(dist[v]+e.cost,dist[e.to])){
        dist[e.to] = dist[v] + e.cost;
        Q.push(State(e.to,dist[e.to]));
      }
    }
  }
  return INF;
}

void init(){
  for(int i = 0 ; i < MAX_P ; i++){
    G[i].clear();
  }
}

int main(){
  int N;
  while(cin >> N, N){
    init();
    Polygon b[MAX_N];
    for(int i = 0 ; i < N ; i++){
      int M;
      cin >> M; b[i].resize(M);
      for(int j = 0 ; j < M ; j++){
        cin >> b[i][j].x >> b[i][j].y;
      }
    }
    Point s,t;
    Line l;
    cin >> s.x >> s.y >> t.x >> t.y;
    cin >> l.s.x >> l.s.y >> l.t.x >> l.t.y;
    int n = -1;
    for(int i = 0 ; i < N ; i++){
      if(containPP(b[i],s) != 0){
        n = i;
        L = b[n];
        break;
      }
    }
    int rn = -1;
    Point rs = reflection(l,s);
    for(int i = 0 ; i < N ; i++){
      if(containPP(b[i],rs) != 0){
        rn = i;
        R = b[rn];
        break;
      }
    }
    Point rt = reflection(l,t);
    if(n == -1 || rn == -1 ||
       containPP(R,rt) == 0){
      cout << "impossible" << endl;
      continue;
    }

    int size = L.size();
    int rsize = R.size();
    int src,dst;
    for(int i = 0 ; i < size ; i++){
      L[i] = reflection(l,L[i]);
    }
    set<Point> st;
    for(int i = 0 ; i < size ; i++){
      if(st.find(L[i]) == st.end()){
        st.insert(L[i]);
      }
    }

    for(int i = 0 ; i < rsize ; i++){
      if(st.find(R[i]) == st.end()){
        st.insert(R[i]);
      }
    }
    s = reflection(l,s);
    t = reflection(l,t);
    if(st.find(s) == st.end()){ st.insert(s); }
    if(st.find(t) == st.end()){ st.insert(t); }
    vector<Point> vec;
    for(auto it = st.begin() ; it != st.end() ; ++it){
      vec.push_back(*it);
    }
    size = vec.size();
    for(int i = 0 ; i < size ; i++){
      for(int j = i+1 ; j < size ; j++){
        Segment seg(vec[i],vec[j]);
        if(containPS(L,seg) && containPS(R,seg)){
          double d = dist(vec[i],vec[j]);
          G[i].push_back(Edge(j,d));
          G[j].push_back(Edge(i,d));
        }
      }
      if(s == vec[i]){ src = i; }
      if(t == vec[i]){ dst = i; }
    }
    double res = dijkstra(src,dst);
    if(res == INF){
      cout << "impossible" << endl;
    }else{
      printf("%.10f\n",res);
    }
  }
  return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 1372
final_rank: 4

code_snippet: // * template

#include <bits/stdc++.h>
#ifdef LOCAL
#include "dump.hpp"
#else
#define dump(...)
#endif

using namespace std;

template<class T> inline void chmax(T &a, const T &b) { if(a < b) a = b; }
template<class T> inline void chmin(T &a, const T &b) { if(a > b) a = b; }

template<class T, class U> inline void fill_array(T &e, const U &v) { e = v; }
template<class T, class U, size_t s> inline void fill_array(T (&a)[s], const U &v) {for(auto&e:a)fill_array(e,v);}
template<class T, class U, size_t s> inline void fill_array(array<T, s> &a, const U &v) {for(auto&e:a)fill_array(e,v);}
template<class T, class U> inline void fill_array(vector<T> &a, const U &v) {for(auto&e:a)fill_array(e,v);}

struct range {
	typedef int Int;
	struct iter {
		Int i;
		const Int s;
		iter(const Int &i_, const Int &s_):i(i_), s(s_) {}
		bool operator!=(const iter &r) const { return s > 0 ? i < r.i : i > r.i; }
		const Int &operator*() const { return i; }
		iter &operator++() { i += s; return *this; }
	};
	const Int f, l, s;
	range(const Int &f_, const Int &l_, const Int &s_):f(f_), l(l_), s(s_) {}
	range(const Int &f_, const Int &l_):f(f_), l(l_), s(1) {}
	range(const Int &num):f(0), l(num), s(1) {}
	iter begin() const { return iter(f, s); }
	iter end() const { return iter(l, s); }
};

// * geometry library

typedef double Real;
constexpr Real EPS = 1e-7;
const Real PI = acos((Real)-1);
inline int sign(Real d) { return d > EPS ? 1 : d < -EPS ? -1 : 0; }

struct point {
	Real x, y;
	explicit point():x(0), y(0) {}
	explicit point(Real x_, Real y_):x(x_), y(y_) {}
	point operator+(const point &p) const { return point(x + p.x, y + p.y); }
	point operator-(const point &p) const { return point(x - p.x, y - p.y); }
	point operator*(const point &p) const { return point(x * p.x - y * p.y, x * p.y + y * p.x); }
	point operator*(Real s) const { return point(x * s, y * s); }
	point operator/(Real s) const { return point(x / s, y / s); }
	bool operator<(const point &p) const { return sign(x - p.x) == -1 || (sign(x - p.x) == 0 && sign(y - p.y) == -1); }
	bool operator==(const point &p) const { return sign(x - p.x) == 0 && sign(y - p.y) == 0; }
	bool operator!=(const point &p) const { return !(*this == p); }
};

inline istream &operator>>(istream &is, point &p) {
	return is >> p.x >> p.y;
}

inline ostream &operator<<(ostream &os, const point &p) {
	return os << '(' << p.x << ", " << p.y << ')';
}

struct line : public array<point, 2> {
	line(const point &a, const point &b) { at(0) = a; at(1) = b; }
};

struct segment : public array<point, 2> {
	segment(const point &a, const point &b) { at(0) = a; at(1) = b; }
};

typedef vector<point> polygon;

inline Real norm(const point &p) {
	return p.x * p.x + p.y * p.y;
}

inline Real abs(const point &p) {
	return sqrt(norm(p));
}

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

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

enum { CCW = 1, CW = -1, BACK = 2, FRONT = -2, ON = 0};
inline int ccw(const point &a, const point &b, const point &c) {
	const point p = b - a;
	const point q = c - a;
	const int sign_cross = sign(cross(p, q));
	if(sign_cross == 1) return CCW;
	if(sign_cross == -1) return CW;
	if(sign(dot(p, q)) == -1) return BACK;
	if(sign(norm(p) - norm(q)) == -1) return FRONT;
	return ON;
}

// ??????????§??????¨??????????????????a, b, c???????????????
// c??????a??????b??????????¨?????????§???????§????????????¨?????????????????¨?????????????????????
// + : ?????¨
// 0 : ?????? or A = B
// - : ?????¨
inline int judge(const point &a, const point &b, const point &c) {
	return sign(cross(a, c)) - sign(cross(b, c)) - sign(cross(a, b));
}

inline point project(const line &l, const point &p) {
	const point a = p - l[0];
	const point b = l[1] - l[0];
	return l[0] + b * (dot(a, b) / norm(b));
}

inline point reflect(const line &l, const point &p) {
	const point t = project(l, p);
	return t + (t - p);
}

inline bool intersect(const segment &s, const point &p) {
	return ccw(s[0], s[1], p) == ON;
}

inline bool intersect(const segment &a, const segment &b) {
	return ccw(a[0], a[1], b[0]) * ccw(a[0], a[1], b[1]) <= 0
		&& ccw(b[0], b[1], a[0]) * ccw(b[0], b[1], a[1]) <= 0;
}

inline Real dist(const point &a, const point &b) {
	return abs(a - b);
}

inline bool contain(const polygon &P, const point &p) {
	bool res = false;
	for(int i = 0; i < P.size(); ++i) {
		point v1 = P[i] - p;
		point v2 = P[(i + 1) % P.size()] - p;
		if(v1.y > v2.y) swap(v1, v2);
		if(sign(cross(v1, v2)) == 0 && sign(dot(v1, v2)) <= 0) return true; // on edge
		if(sign(v1.y) <= 0 && sign(v2.y) == 1 && sign(cross(v1, v2)) == 1) res = !res;
	}
	return res;
}

inline bool contain(const polygon &P, const segment &s) {
	const Real c = (EPS * 100);

	if(!contain(P, s[0] + (s[1] - s[0]) * c)) return false;
	if(!contain(P, s[1] + (s[0] - s[1]) * c)) return false;

	const int n = P.size();
	for(int i = 0; i < n; ++i) {
		const point &curr = P[i];
		const point &next = P[(i + 1) % n];

		const int c1 = ccw(curr, next, s[0]);
		const int c2 = ccw(curr, next, s[1]);
		if(c1 == ON && c2 == ON) return true;
		if(c1 * c2 == -1 && ccw(s[0], s[1], curr) * ccw(s[0], s[1], next) == -1) return false;
	}

	for(int i = 0; i < n; ++i) {
		const point &prev = P[(i - 1 + n) % n];
		const point &curr = P[i];
		const point &next = P[(i + 1) % n];

		if(curr != s[0] && curr != s[1] && intersect(s, curr)) {
			if(judge(prev - curr, next - curr, s[0] - curr) > 0) return false;
			if(judge(prev - curr, next - curr, s[1] - curr) > 0) return false;
		}
	}

	return true;
}

// * solve

typedef pair<int, Real> edge;
typedef vector<vector<edge>> graph;

vector<Real> dijkstra(int s, const graph &G) {
	typedef pair<Real, int> P;
	const int n = G.size();

	vector<Real> dis(n, numeric_limits<Real>::max());
	priority_queue<P, vector<P>, greater<P>> que;

	dis[s] = 0;
	que.emplace(0, s);

	while(!que.empty()) {
		const auto d = que.top().first;
		const auto v = que.top().second;
		que.pop();

		if(dis[v] < d) continue;

		for(const auto &e : G[v]) {
			const auto next_dis = d + e.second;
			if(dis[e.first] > next_dis) {
				dis[e.first] = next_dis;
				que.emplace(next_dis, e.first);
			}
		}
	}

	return dis;
}

Real dijkstra(int s, int g, const graph &G) {
	return dijkstra(s, G)[g];
}

int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	cout.setf(ios::fixed);
	cout.precision(10);

	for(int n; cin >> n && n;) {
		vector<polygon> building;
		building.reserve(n);

		for(const int i : range(n)) {
			int m;
			cin >> m;

			polygon P;
			P.reserve(m);

			for(const int j : range(m)) {
				point p;
				cin >> p;
				P.emplace_back(p);
			}
			building.emplace_back(P);
		}

		point s, g, l1, l2;
		cin >> s >> g >> l1 >> l2;

		const line L(l1, l2);
		const point r_s = reflect(L, s);
		const point r_g = reflect(L, g);

		int idx = -1, r_idx = -1;
		for(const int i : range(n)) {
			if(contain(building[i], s) && contain(building[i], g)) {
				idx = i;
			}
			else if(contain(building[i], r_s) && contain(building[i], r_g)) {
				r_idx = i;
			}
		}

		if(idx == -1 || r_idx == -1) {
			cout << "impossible" << endl;
			continue;
		}

		const polygon &P = building[idx];
		const polygon &r_P = building[r_idx];

		vector<point> points;
		for(const auto &p : P) {
			points.emplace_back(p);
		}

		for(const auto &p : r_P) {
			points.emplace_back(reflect(L, p));
		}

		sort(begin(points), end(points));
		points.erase(unique(begin(points), end(points)), end(points));
		points.emplace_back(s);
		points.emplace_back(g);

		const int V = points.size();
		graph G(V);

		for(const int i : range(V)) {
			for(const int j : range(i + 1, V)) {
				const segment seg(points[i], points[j]), r_seg(reflect(L, points[i]), reflect(L, points[j]));

				if(contain(P, seg) && contain(r_P, r_seg)) {
					const Real d = dist(points[i], points[j]);
					G[i].emplace_back(j, d);
					G[j].emplace_back(i, d);
				}
			}
		}

		const auto ans = dijkstra(V - 2, V - 1, G);
		if(ans == numeric_limits<Real>::max()) {
			cout << "impossible" << endl;
		}
		else {
			cout << ans << endl;
		}
	}

	return EXIT_SUCCESS;
}
accuracy: 1
time_ms: 40
memory_kb: 1364
final_rank: 2

code_snippet: #include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e+10;
const double PI = acos(-1);
int sig(double r) { return (r < -EPS) ? -1 : (r > +EPS) ? +1 : 0; }
inline double ABS(double a){return max(a,-a);}
struct Pt {
	double x, y;
	Pt() {}
	Pt(double x, double y) : x(x), y(y) {}
	Pt operator+(const Pt &a) const { return Pt(x + a.x, y + a.y); }
	Pt operator-(const Pt &a) const { return Pt(x - a.x, y - a.y); }
	Pt operator*(const Pt &a) const { return Pt(x * a.x - y * a.y, x * a.y + y * a.x); }
	Pt operator-() const { return Pt(-x, -y); }
	Pt operator*(const double &k) const { return Pt(x * k, y * k); }
	Pt operator/(const double &k) const { return Pt(x / k, y / k); }
	bool operator < (const Pt &a)const{
		if(sig(x-a.x))return 0>sig(x-a.x);
		return 0>sig(y-a.y);
	}
	double ABS() const { return sqrt(x * x + y * y); }
	double abs2() const { return x * x + y * y; }
	double arg() const { return atan2(y, x); }
	double dot(const Pt &a) const { return x * a.x + y * a.y; }
	double det(const Pt &a) const { return x * a.y - y * a.x; }
};
bool eq(Pt a,Pt b){
	return sig((a-b).abs2())==0;
}
double tri(const Pt &a, const Pt &b, const Pt &c) { return (b - a).det(c - a); }
int iSP(Pt a, Pt b, Pt c) {
	int s = sig((b - a).det(c - a));
	if (s) return s;
	if (sig((b - a).dot(c - a)) < 0) return -2; // c-a-b
	if (sig((a - b).dot(c - b)) < 0) return +2; // a-b-c
	return 0;
}
Pt pLL(Pt a, Pt b, Pt c, Pt d) {
	b = b - a; d = d - c; return a + b * (c - a).det(d) / b.det(d);
}
int iLL(Pt a, Pt b, Pt c, Pt d) {
	if (sig((b - a).det(d - c))) return 1; // intersect
	if (sig((b - a).det(c - a))) return 0; // parallel
	return -1; // correspond
}
bool iSS(Pt a, Pt b, Pt c, Pt d) {
	return (iSP(a, b, c) * iSP(a, b, d) <= 0 && iSP(c, d, a) * iSP(c, d, b) <= 0);
}
bool iSSstrict(Pt a, Pt b, Pt c, Pt d) {
	return (sig(tri(a, b, c)) * sig(tri(a, b, d)) < 0 && sig(tri(c, d, a)) * sig(tri(c, d, b)) < 0);
}
Pt hLP(Pt a,Pt b,Pt c){
	return pLL(a,b,c,c+(b-a)*Pt(0,1));
}
Pt tLP(Pt a,Pt b,Pt c){
	Pt H=hLP(a,b,c);
	return H+H-c;
}
int sGP(int n, vector<Pt>p, Pt a) {
	int side = -1, i;
	p.push_back(p[0]);
	for (i = 0; i < n; ++i) {
		Pt p0 = p[i] - a, p1 = p[i + 1] - a;
		if (sig(p0.det(p1)) == 0 && sig(p0.dot(p1)) <= 0) return 0;
		if (p0.y > p1.y) swap(p0, p1);
		if (sig(p0.y) <= 0 && 0 < sig(p1.y) && sig(p0.det(p1)) > 0) side = -side;
	}
	return side;
}
vector<Pt>poly[110];
vector<Pt>hb;
double ijk[11000];
int v[11000];
bool iGSstrict(int t, Pt a, Pt b) {
	for(int i=0;i<poly[t].size();i++){
		if(iLL(a,b,poly[t][i],poly[t][(i+1)%poly[t].size()])==-1)continue;
		if(iSSstrict(a,b,poly[t][i],poly[t][(i+1)%poly[t].size()]))return 1;
	}
	vector<Pt>tmp;
	for(int i=0;i<poly[t].size();i++){
		if(iLL(a,b,poly[t][i],poly[t][(i+1)%poly[t].size()])==-1)continue;
		if(iSS(a,b,poly[t][i],poly[t][(i+1)%poly[t].size()])){
			tmp.push_back(pLL(a,b,poly[t][i],poly[t][(i+1)%poly[t].size()]));
		}
	}
	tmp.push_back(a);
	tmp.push_back(b);
	//if(sGP(poly[t].size(),poly[t],(a*0.99999+b*0.00001))==-1)return 1;
	//if(sGP(poly[t].size(),poly[t],(b*0.99999+a*0.00001))==-1)return 1;
	std::sort(tmp.begin(),tmp.end());
	for(int i=1;i<tmp.size();i++){
		Pt M=(tmp[i-1]+tmp[i])/2;
		if(sGP(poly[t].size(),poly[t],M)==-1)return 1;
	}
//	printf("%d (%f %f) -> (%f %f)\n",t,a.x,a.y,b.x,b.y);
	return 0;
}
int main(){
	int a;
	while(scanf("%d",&a),a){
		for(int i=0;i<110;i++)poly[i].clear();
		for(int i=0;i<a;i++){
			int b;scanf("%d",&b);
			for(int j=0;j<b;j++){
				double X,Y;
				scanf("%lf%lf",&X,&Y);
				poly[i].push_back(Pt(X,Y));
			}
		}
		double X1,Y1,X2,Y2;
		scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
		Pt S1=Pt(X1,Y1);
		Pt G1=Pt(X2,Y2);
		scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
		Pt L1=Pt(X1,Y1);
		Pt L2=Pt(X2,Y2);
		Pt S2=tLP(L1,L2,S1);
		Pt G2=tLP(L1,L2,G1);
		int f1=-1;
		int f2=-1;
		int t1=-1;
		int t2=-1;
		for(int i=0;i<a;i++){
			int n=poly[i].size();
			if(~sGP(n,poly[i],S1))f1=i;
			if(~sGP(n,poly[i],S2))f2=i;
			if(~sGP(n,poly[i],G1))t1=i;
			if(~sGP(n,poly[i],G2))t2=i;
		}
		if(f1==-1||f2==-1||t1==-1||t2==-1||f1!=t1||f2!=t2){
			printf("impossible\n");continue;
		}
		hb.clear();
		for(int i=0;i<poly[f1].size();i++)hb.push_back(poly[f1][i]);
		for(int i=0;i<poly[f2].size();i++)hb.push_back(tLP(L1,L2,poly[f2][i]));
	/*	for(int i=0;i<poly[f1].size();i++){
			for(int j=0;j<poly[f2].size();j++){
				Pt v1=tLP(L1,L2,poly[f2][j]);
				Pt v2=tLP(L1,L2,poly[f2][(j+1)%poly[f2].size()]);
				if(iSSstrict(poly[f1][i],poly[f1][(i+1)%poly[f1].size()],v1,v2)){
					hb.push_back(pLL(poly[f1][i],poly[f1][(i+1)%poly[f1].size()],v1,v2));
				}
			}
		}*/
		int S=hb.size();
		hb.push_back(S1);
		int T=hb.size();
		hb.push_back(G1);
		int sz=hb.size();
		for(int i=0;i<11000;i++){
			ijk[i]=999999999;v[i]=0;
		}
		ijk[S]=0;
	//	for(int i=0;i<sz;i++)printf("%f %f\n",hb[i].x,hb[i].y);
		for(int i=0;i<sz;i++){
			double dist=99999999;
			int at=-1;
			for(int j=0;j<sz;j++){
				if(!v[j]&&ijk[j]<dist){
					dist=ijk[j];
					at=j;
				}
			}
			if(!~at)break;
		//	printf("%f %f: %f\n",hb[at].x,hb[at].y,ijk[at]);
			v[at]=1;
			Pt from1=hb[at];
			Pt from2=tLP(L1,L2,hb[at]);
			for(int j=0;j<sz;j++){
				if(v[j])continue;
				if(ijk[j]<dist+(from1-hb[j]).ABS())continue;
				Pt to1=hb[j];
				Pt to2=tLP(L1,L2,to1);
		//		printf("%f %f %f %f\n",from1.x,from1.y,from2.x,from2.y);
				if(iGSstrict(f1,from1,to1)){
			//		printf("(%f %f) -> (%f %f): hit on 1\n",from1.x,from1.y,to1.x,to1.y);
					continue;
				}
				if(iGSstrict(f2,from2,to2)){
			//		printf("(%f %f) -> (%f %f): hit on 2\n",from1.x,from1.y,to1.x,to1.y);
					continue;
				}
				ijk[j]=dist+(from1-hb[j]).ABS();
			}
		}
		if(ijk[T]>99999999)printf("impossible\n");
		else printf("%.12f\n",ijk[T]);
	}
}
accuracy: 1
time_ms: 70
memory_kb: 1276
final_rank: 1

code_snippet: #include <string> 
#include <iomanip>
#include <algorithm> 
#include <cfloat> 
#include <climits> 
#include <cmath> 
#include <complex> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <functional> 
#include <iostream> 
#include <map> 
#include <memory> 
#include <queue> 
#include <set> 
#include <sstream> 
#include <stack> 
#include <utility> 
#include <vector> 

#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define ALL(x) (x).begin(),(x).end() 
typedef long long ll;
using namespace std; 
const double eps = 1e-10;
const double INF = 1e+10;

typedef complex<double> P;
namespace std{
    bool operator<(const P &a, const P &b){
        return a.real() != b.real() ? a.real() < b.real(): a.imag() < b.imag();
    }
};
inline double dot(const P &a, const P &b){
    return real(conj(a) * b);
}
inline double cross(const P &a, const P &b){
    return imag(conj(a) * b);
}
int ccw(const 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 (norm(b) < norm(c)+eps)  return -2;  // a-b-c
    return 0;                           // a-c-b
}
struct Line : public vector<P> {
    Line() { }
    Line(const P &a, const P &b) {
        push_back(a); push_back(b);
    }
};
inline bool parallel(const Line &s, const Line &t){
    return abs(cross(s[1]-s[0], t[1]-t[0])) < eps;
}
inline bool orthogonal(const Line &s, const Line &t){
    return abs(dot(s[1]-s[0], t[1]-t[0])) < eps;
}
P projection(const Line &s, const P &a){
    P v = s[1] - s[0];
    return s[0] + dot(v, a - s[0]) / abs(v) / abs(v) * v;
}
P reflection(const Line &s, const P &a){
    P p = projection(s, a);
    return 2.0 * p - a;
}
struct Segment : public Line {
    Segment(const P &a, const P &b) : Line(a,b) { }
};
struct Circle{
    P o;
    double r;
    Circle() { }
    Circle(const P &o, double r) : o(o), r(r) { }
    Circle(double x, double y, double r) : o(x,y), r(r) { }
    inline bool contains(const P &p) const{
        return abs(p-o) < r + eps;
    }
    inline bool inside(const P &p) const{
        return abs(p-o) < r - eps;
    }
    pair<Line,Line> tangent(const P &p) const{
        vector<Line> res;
        double d = abs(p - o), s = r*r / d, t = sqrt(r*r-s*s);
        P q = o + s/d * (p - o), e = (p - o) * P(0, 1/d); 
        return make_pair(Line(p,q+e*t), Line(p,q-e*t));
    }
};
typedef vector<P> Polygon;
#define curr(p,i) p[i]
#define next(p,i) p[(i+1)%p.size()]
inline bool intersectSS(const Segment &s, const Segment &t){
    return ccw(s[0],s[1],t[0]) * ccw(s[0],s[1],t[1]) <= 0 &&
           ccw(t[0],t[1],s[0]) * ccw(t[0],t[1],s[1]) <= 0;
}
// TODO:端点の扱いが雑なのを何とかする．
P crosspointSS(const Segment &s, const Segment &t){
    double a = cross(s[1] - s[0], t[1] - t[0]);
    double b = cross(s[1] - s[0], s[1] - t[0]);
    if(abs(a) < eps && abs(b) < eps) return s[0];   // same line
    // if(abs(a) < eps) assert(false);
    return t[0] + b/a * (t[1] - t[0]);
}

enum {OUT, ON, IN};
int contains(const Polygon &p, const P &q){
    bool in = false;
    for(int i = 0; i < p.size(); ++i){
        P a = curr(p, i) - q, b = next(p,i) - q;
        if(imag(a) > imag(b)) swap(a,b);
        if(imag(a) <= 0 && 0 < imag(b))
            if(cross(a,b) < -eps) in = !in;
        if(abs(cross(a,b)) < eps && dot(a,b) < eps) return ON;
    }
    return in ? IN: OUT;
}
int contains(const Polygon &p, const Segment &s){
    vector<pair<double, P> > ps;
    for(int i=0;i<p.size();++i)
        if(intersectSS(s, Segment(p[i], next(p,i)))){
            P q = crosspointSS(s, Segment(p[i], next(p,i)));
            ps.push_back(make_pair(abs(q-s[0]), q));
        }
    ps.push_back(make_pair(0, s[0]));
    ps.push_back(make_pair(abs(s[1]-s[0]), s[1]));
    sort(ALL(ps));
    bool on = true;
    for(int i=0;i<ps.size()-1;++i){
        P q = (ps[i].second+ps[i+1].second) * 0.5;
        int r = contains(p, q);
        if(r == OUT) return OUT;
        on = on && r == ON;
    }
    return on ? ON: IN;
}
P crosspointLL(const Line &s, const Line &t){
    double a = cross(s[1] - s[0], t[1] - t[0]);
    double b = cross(s[1] - s[0], s[1] - t[0]);
    if(abs(a) < eps && abs(b) < eps) return s[0];   // same line
    // if(abs(a) < eps) assert(false);
    return t[0] + b/a * (t[1] - t[0]);
}

int main(){
    for(;;){
        int N;
        cin >> N;
        if(N == 0) return 0;
        vector<Polygon> pol(N);
        for(int i = 0; i < N; ++i){
            int m;
            cin >> m;
            pol[i].resize(m);
            for(int j = 0; j < m; ++j){
                int x, y;
                cin >> x >> y;
                pol[i][j] = P(x,y);
            }
        }
        int sx, sy, gx, gy;
        cin >> sx >> sy >> gx >> gy;
        P S(sx,sy), G(gx,gy);
        cin >> sx >> sy >> gx >> gy;
        Line L(P(sx,sy), P(gx,gy));

        P A = reflection(L, S), B = reflection(L, G);
        int id1 = 0, id2 = -1;
        for(int i = 0; i < N; ++i){
            if(contains(pol[i], S) != OUT)
                id1 = i;
            if(contains(pol[i],A) != OUT && contains(pol[i],B) != OUT)
                id2 = i;
        }
        if(id2 < 0){
            cout << "impossible" << endl;
            continue;
        }
        Polygon p1 = pol[id1], p2 = pol[id2], ps;
        reverse(ALL(p2));
        EACH(i, p2) *i = reflection(L, *i);
        ps.push_back(S); ps.push_back(G);
        EACH(i, p1)
            if(contains(p1, *i) != OUT && contains(p2, *i) != OUT)
                ps.push_back(*i);
        EACH(i, p2)
            if(contains(p1, *i) != OUT && contains(p2, *i) != OUT)
                ps.push_back(*i);
        int m = ps.size();
        vector<vector<double> > d(m, vector<double>(m));
        for(int i=0;i<m;++i) for(int j=i+1;j<m;++j){
            Segment ss(ps[i], ps[j]);
            if(contains(p1, ss) != OUT && contains(p2, ss) != OUT)
                d[i][j] = d[j][i] = abs(ps[j]-ps[i]);
            else
                d[i][j] = d[j][i] = INF;
        }
        for(int k=0;k<m;++k)for(int i=0;i<m;++i)for(int j=0;j<m;++j)
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
        if(d[0][1] < INF)
            cout << fixed << setprecision(10) << d[0][1] << endl;
        else
            cout << "impossible" << endl;
    }
}
accuracy: 1
time_ms: 240
memory_kb: 1408
final_rank: 7

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <iterator>
#include <assert.h>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef double R;
	const R INF = 1e8;
	const R EPS = 1e-8;
	const R PI = 3.1415926535897932384626;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	inline P unit(const P& p){return p/abs(p);}
	inline P proj(const P &s, const P &t){return t*inp(s, t)/norm(t);}
	inline int ccw(const P &s, const P &t, const P &p, int adv=0){
		int res = sig(outp(t-s, p-s));
		if(res || !adv) return res;
		if(sig(inp(t-s, p-s)) < 0) return -2;	// p-s-t
		if(sig(inp(s-t, p-t)) < 0) return 2;	// s-t-p
		return 0;								// s-p-t
	}
	
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{	// segment
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			if(!sig(norm(p - at(0))) || !sig(norm(p - at(1)))) return BORDER;
			return !sig(abs(at(0)-p) + abs(at(1) - p) - abs(at(0) - at(1)));
		}
	};
	P crosspoint(const L &l, const L &m);
	struct G : public vector<P>{
		G(size_type size=0):vector(size){}
		S edge(int i)const {return S(at(i), at(i+1 == size() ? 0 : i+1));}
		BOOL contains(const P &p)const {
			R sum = .0;
			REP(i, size()){
				if(S(at(i), at((i+1)%size())).online(p)) return BORDER;	// online
				sum += arg((at(i) - p) / (at((i+1)%size()) - p));
			}
			return !!sig(sum);
		}
	};

	inline P proj(const P &s, const L &t){return t[0] + proj(s-t[0], t[1]-t[0]);}
	inline P reflect(const P &s, const L &t){return 2.*proj(s, t) - s;}
	BOOL intersect(const S &s, const S &t){
		const int p = ccw(t[0], t[1], s[0], 1) * ccw(t[0], t[1], s[1], 1);
		const int q = ccw(s[0], s[1], t[0], 1) * ccw(s[0], s[1], t[1], 1);
		return (p>0||q>0) ? FALSE : (!p||!q) ? BORDER : TRUE;
	}
	
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0]; // same line
		if(abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
		return m[0] + B / A * (m[1] - m[0]);
	}

#undef SELF
#undef at
}

using namespace geom;


namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y < b.Y;}
	bool operator==(const P &a, const P &b){return !sig(norm(a-b));}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
	istream& operator>>(istream &is, L &l){l.resize(2);return is >> l[0] >> l[1];}
}


int n, m;


int main(){
	ios::sync_with_stdio(false);
	while(cin >> n, n){
		vector<G> poly(n);
		REP(i, n){
			int x;
			cin >> x;
			poly[i].resize(x);
			REP(j, x) cin >> poly[i][j];
		}
		P s, t;
		cin >> s >> t;
		L l;
		cin >> l;
		int pccw = ccw(l[0], l[1], s);
		vector<G> tar;
		if(![&](){
			REP(i, n){
				if(pccw != ccw(l[0], l[1], poly[i][0]))
					REP(j, poly[i].size()) poly[i][j] = reflect(poly[i][j], l);
				int f = !!poly[i].contains(s) + !!poly[i].contains(t);
				if(f == 1) return 0;
				if(f == 2) tar.push_back(poly[i]);
			}
			if(tar.size() != 2) return 0;
			vector<P> p;
			p.push_back(s);
			p.push_back(t);
			FOR(it, tar[0]) p.push_back(*it);
			FOR(it, tar[1]) p.push_back(*it);
			n = p.size();
			vector<vector<R>> g(n, vector<R>(n, INF));
			REP(i, n) g[i][i] = 0;
			REP(i, n)REP(j, i){
				S s(p[i], p[j]);
				if([](const vector<G> &tar, const S &s){
					vector<P> p;
					REP(k, 2){
						const G &t = tar[k];
						REP(i, t.size()){
							const auto & e = t.edge(i);
							if(!sig(outp(e.dir(), s.dir()))) continue;
							int f = intersect(e, s);
							if(f == TRUE) return 0;
							if(f == BORDER) p.push_back(crosspoint(e, s));
						}
					}
					sort(ALL(p));UNIQUE(p);
					REP(i, (int)p.size() - 1){
						const P q = (p[i] + p[i+1]) * .5;
						if(!tar[0].contains(q) || !tar[1].contains(q)) return 0;
					}
					return 1;
				}(tar, s)) g[i][j] = g[j][i] = abs(s.dir());
			}
			REP(k, n)REP(i, n)REP(j, n) g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
			if(g[0][1] > INF - EPS) return 0;
			printf("%.14f\n", g[0][1]);
			return 1;
		}()) puts("impossible");
	}
	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 1500
final_rank: 8

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <iterator>
#include <assert.h>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef double R;
	const R INF = 1e8;
	const R EPS = 1e-8;
	const R PI = 3.1415926535897932384626;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	inline P unit(const P& p){return p/abs(p);}
	inline P proj(const P &s, const P &t){return t*inp(s, t)/norm(t);}
	inline int ccw(const P &s, const P &t, const P &p, int adv=0){
		int res = sig(outp(t-s, p-s));
		if(res || !adv) return res;
		if(sig(inp(t-s, p-s)) < 0) return -2;	// p-s-t
		if(sig(inp(s-t, p-t)) < 0) return 2;	// s-t-p
		return 0;								// s-p-t
	}
	
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{	// segment
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			if(!sig(norm(p - at(0))) || !sig(norm(p - at(1)))) return BORDER;
			return !sig(abs(at(0)-p) + abs(at(1) - p) - abs(at(0) - at(1)));
		}
	};
	struct C : public P{
		C(){}
		C(const P& p, const R r):P(p), r(r){}
		R r;
		BOOL inside(const P& p)const { return less(norm(p-SELF), r*r);}
	};
	struct F : public C{
		R s, t;
		F(const C &c, R ss, R tt):C(c), s(ss), t(tt){
			if(PI < s) s -= 2*PI;
			if(PI < t) t -= 2*PI;
		}
		BOOL inside(const P& p)const {
			P v = p - SELF;
			if(!sig(norm(v))) return BORDER;
			R a = arg(v);
			if(t < s){
				if((!less(s, a) && !less(a, t)) || !less(norm(v), r*r)) return FALSE;
				return less(s, a) | less(a, t) | less(norm(v), r*r);
			}else{
				if(!less(s, a) || !less(a, t) || !less(norm(v), r*r)) return FALSE;
				return less(s, a) | less(a, t) | less(norm(v), r*r);
			}
		}
	};
	P crosspoint(const L &l, const L &m);
	struct G : public vector<P>{
		G(size_type size=0):vector(size){}
		S edge(int i)const {return S(at(i), at(i+1 == size() ? 0 : i+1));}
		BOOL contains(const P &p)const {
			R sum = .0;
			REP(i, size()){
				if(S(at(i), at((i+1)%size())).online(p)) return BORDER;	// online
				sum += arg((at(i) - p) / (at((i+1)%size()) - p));
			}
			return !!sig(sum);
		}
		R area()const {
			R sum = 0;
			REP(i, size()) sum += outp(at(i), at((i+1)%size()));
			return abs(sum / 2.);
		}
		
		G convex_hull(bool online = false) {
			if(size() < 2) return *this;
			sort(ALL(*this));
			G r;
			r.resize((int)size()*2);
			int k=0;
			for(int i=0;i<size();r[k++]=at(i++))
				while(k>1 && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			int t = k;
			for(int i=(int)size()-1;i>=0;r[k++]=at(i--))
				while(k>t && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			r.resize(k-1);
			return r;
		}
		G cut(const L &l)const {
			G g;
			REP(i, size()){
				const S &s = edge(i);
				if(ccw(l[0], l[1], s[0], 0) >= 0) g.push_back(s[0]);
				if(ccw(l[0], l[1], s[0], 0) * ccw(l[0], l[1], s[1], 0) < 0)
					g.push_back(crosspoint(s, l));
			}
			return g;
		}
		G Voronoi(const vector<P> &p, const int t)const {
			G g = *this;
			REP(i, p.size())if(i!=t){
				const P m = (p[t]+p[i])*0.5;
				g = g.cut(L(m, m+(p[i]-p[t])*P(0, 1)));
			}
			return g;
		}
	};

	inline P proj(const P &s, const L &t){return t[0] + proj(s-t[0], t[1]-t[0]);}
	inline P reflect(const P &s, const L &t){return 2.*proj(s, t) - s;}
	inline S reflect(const S &s, const L &t){return S(reflect(s[0], t), reflect(s[1], t));}
	BOOL intersect(const S &s, const S &t){
		const int p = ccw(t[0], t[1], s[0], 1) * ccw(t[0], t[1], s[1], 1);
		const int q = ccw(s[0], s[1], t[0], 1) * ccw(s[0], s[1], t[1], 1);
		return (p>0||q>0) ? FALSE : (!p||!q) ? BORDER : TRUE;
	}
	BOOL intersect(const S &s, const L &l){
		if(l.online(s[0]) || l.online(s[1])) return BORDER;
		return (sig(outp(l.dir(), s[0]-l[0])) * sig(outp(l.dir(), s[1]-l[0])) <= 0);
	}
	R dist2(const L &l, const P &p){return norm(outp(l.dir(), p - l[0])) / norm(l.dir());}
	R dist2(const S &s, const P &p){
		if(inp(p-s[0],  s.dir()) < EPS) return norm(p - s[0]);
		if(inp(p-s[1], -s.dir()) < EPS) return norm(p - s[1]);
		return dist2((const L &)s, p);
	}
	R dist2(const S &s, const L &l){
		return intersect(s, l) ? .0 : min(dist2(l, s[0]), dist2(l, s[1]));
	}
	R dist2(const S &s, const S &t){
		return intersect(s, t) ? .0 : min(min(dist2(s, t[0]), dist2(t, s[0])), 
									   	  min(dist2(s, t[1]), dist2(t, s[1])));
	}
	template <class T> R dist2(const G &g, const T& t){ // todo: 内部に完全に含まれる場合
		R res = INF;
		REP(i, g.size()) res = min(res, dist2(g.edge(i), t));
		return res;
	}
	template<class S, class T> R dist(const S& s, const T& t){return sqrt(dist2(s, t));}
	inline BOOL intersect(const C &a, const C &b){
		return less((a.r-b.r)*(a.r-b.r), norm(a-b)) + less(norm(a-b), (a.r+b.r)*(a.r+b.r)) - 1;
	}
	inline BOOL intersect(const C &c, const L &l){
		return less(dist2(l, c), c.r*c.r);
	}
	inline BOOL intersect(const C &c, const S &s){
		int d = less(dist2(s, c), c.r*c.r);
		if(d != TRUE) return d;
		int p = c.inside(s[0]), q = c.inside(s[1]);
		return (p<0 || q<0) ? BORDER : p&q;
	}
	
	/*
	 * CCWでs[0]->s[1]にかけてが共通部分
	 */
	inline S crosspoint(const C &c1, const C &c2){
		if(!intersect(c1, c2)) return S();
		R d = abs(c1 - c2);
		R x = (c1.r*c1.r - c2.r*c2.r + d*d) / (2*d);
		R h = sqrt(c1.r*c1.r - x*x);
		P u = unit(c2-c1);
		return S(c1 + u*x + u*P(0,-1)*h, c1 + u*x + u*P(0,1)*h);
	}
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0]; // same line
		if(abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
		return m[0] + B / A * (m[1] - m[0]);
	}
	inline S crosspoint(const C &c, const L &l){
		R d2 = dist2(l, c);
		if(c.r*c.r+EPS < d2) return S();
		P m = proj(c, l);
		P u = unit(l[1]-l[0]);
		R d = sqrt(c.r*c.r - d2);
		return S(m+u*d, m-u*d);
	}
	inline vector<P> crosspoint(const C &c, const S &s){
		vector<P> res = crosspoint(c, (const L&)s);
		RREP(i, res.size()){
			if(inp(res[i]-s[0], s.dir())*inp(res[i]-s[1], -s.dir())<EPS)
				res.erase(res.begin() + i);
		}
		return res;
	}
	inline R commonarea(const C &a, const C &b){
		if(less(norm(a-b), (a.r-b.r)*(a.r-b.r)) == TRUE) return min(a.r*a.r, b.r*b.r)*PI;
		if(less((a.r+b.r)*(a.r+b.r), norm(a-b)) == TRUE) return .0;
		double d = abs(a-b);
		double rc = (d*d + a.r*a.r - b.r*b.r) / (2*d);
		double theta = acos(rc / a.r);
		double phi = acos((d - rc) / b.r);
		return a.r*a.r*theta + b.r*b.r*phi - d*a.r*sin(theta);
	}
	vector<L> CommonTangent(C c1, C c2){
		if(c1.r > c2.r) swap(c1, c2);
		double d = abs(c1-c2);
		vector<L> res;
		if(d < EPS) return res;
		if(d + EPS > c1.r + c2.r){
			// 内接線
			P crs = (c1*c2.r + c2*c1.r) / (c1.r + c2.r);
			double rad = asin(c1.r/abs(crs-c1));
			res.push_back(L(crs, crs + (c1-crs)*polar(1., rad)));
			res.push_back(L(crs, crs + (c1-crs)*polar(1., -rad)));
		}
		if(c1.r + d + EPS > c2.r){
			// 外接線
			double rad = 0.5*PI+asin((c2.r-c1.r) / d);
			P v = unit(c2-c1)*polar(1., rad);
			if(c1.r + d - EPS < c2.r){
				res.push_back(L(c1+v*c1.r, c1+v*c1.r+(c1-c2)*P(0, 1)));
			}else{
				res.push_back(L(c1+v*c1.r, c2+v*c2.r));
				v = 2.*proj(v, c2-c1) - v;
				res.push_back(L(c1+v*c1.r, c2+v*c2.r));
			}
		}
		return res;
	}
	
	
	struct Arrangement{
		struct AEdge{
			int u, v, t;
			R cost;
			AEdge(int u=0, int v=0, int t=0, R cost=0)
				:u(u), v(v), t(t), cost(cost){}
		};
		typedef vector<vector<AEdge>> AGraph;
		vector<P> p;
		AGraph g;
		Arrangement(){}
		Arrangement(vector<S> seg){
			int m = seg.size();
			REP(i, m){
				p.push_back(seg[i][0]);
				p.push_back(seg[i][1]);
				REP(j, i) if(sig(outp(seg[i].dir(), seg[j].dir())) && intersect(seg[i], seg[j]) == TRUE)
					p.push_back(crosspoint(seg[i], seg[j]));
			}
			sort(ALL(p)); UNIQUE(p);
			int n=p.size();
			g.resize(n);
			REP(i, m){
				S &s = seg[i];
				vector<pair<R, int>> ps;
				REP(j, n) if(s.online(p[j])) ps.emplace_back(norm(p[j] - s[0]), j);
				sort(ALL(ps));
				REP(j, (int)ps.size()-1){
					const int u=ps[j].second;
					const int v=ps[j+1].second;
					g[u].emplace_back(u, v, 0, abs(p[u] - p[v]));
					g[v].emplace_back(v, u, 0, abs(p[u] - p[v]));
				}
			}
		}
		
		int getIdx(P q){
			auto it = lower_bound(ALL(p), q);
			if(it == p.end() || *it != q) return -1;
			return it - p.begin();
		}
	};

	struct min_ball {
		P center;
		R radius2;
		min_ball(const vector<P>& p) {
			FOR(it, p) ps.push_back(*it);
		}
		min_ball& compile() {
			m = 0;
			center = P(0, 0);
			radius2 = -1;
			make_ball(ps.end());
			return *this;
		}
	private:
		list<P> ps;
		list<P>::iterator supp_end;
		int m;
		P v[3], c[3];
		R z[3], r[3];
		void pop() { --m; }
		void push(const P& p) {
			if (m == 0) {
				c[0] = p; r[0] = 0;
			} else {
				R e = norm(p-c[m-1]) - r[m-1];
				P delta = p - c[0];
				v[m] = p - c[0];
				for (int i = 1; i < m; ++i)
					v[m] -= v[i] * inp(v[i], delta) / z[i];
				z[m] = inp(v[m], v[m]);
				c[m] = c[m-1] + e*v[m]/z[m]*.5;
				r[m] = r[m-1] + e*e/z[m]*.25;
			}
			center	= c[m];
			radius2 = r[m]; ++m;
		}
		void make_ball(list<P>::iterator i) {
			supp_end = ps.begin();
			if (m == 3) return;
			for (list<P>::iterator k = ps.begin(); k != i; ) {
				list<P>::iterator j = k++;
				if (norm(*j-center) > radius2) {
					push(*j); make_ball(j); pop();
					move_to_front(j);
				}
			}
		}
		void move_to_front(list<P>::iterator j) {
			if (supp_end == j) ++supp_end;
			ps.splice (ps.begin(), ps, j);
		}
	};

#undef SELF
#undef at
}

using namespace geom;


namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y < b.Y;}
	bool operator==(const P &a, const P &b){return !sig(norm(a-b));}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
	istream& operator>>(istream &is, L &l){l.resize(2);return is >> l[0] >> l[1];}
	istream& operator>>(istream &is, C &c){return is >> (P &)c >> c.r;}
	const double B = 3;
	const double Z = 100;
	ostream& operator<<(ostream &os, const P &p){return os << "circle("<<Z*(B+p.X)<<", "<<Z*(B-p.Y)<<", 2)";}
	ostream& operator<<(ostream &os, const C &c){return os << "circle("<<Z*(B+c.X)<<", "<<Z*(B-c.Y)<<", "<<Z*(c.r)<<")";}
	ostream& operator<<(ostream &os, const S &s){return os << "line("<<Z*(B+s[0].X)<<", "<<Z*(B-s[0].Y)<<", "<<Z*(B+s[1].X)<<", "<<Z*(B-s[1].Y)<<")";}
	ostream& operator<<(ostream &os, const G &g){REP(i, g.size()) cout << g.edge(i) << endl;return os;}
}


int n, m;

vector<vi> visibility(const G &g){
	int n = g.size();
	
	vector<P> tar;
	REP(i, n){
		const S &s = g.edge(i);
		vector<P> intr;
		REP(j, n)REP(k, j)
			if(sig(outp(s.dir(), g[j] - g[k])) && intersect(s, L(g[j], g[k])))
				intr.push_back(crosspoint(s, L(g[j], g[k])));
		sort(ALL(intr));UNIQUE(intr);
		REP(j, (int)intr.size()-1) tar.push_back((intr[j]+intr[j+1])*.5);
	}
	sort(ALL(tar));UNIQUE(tar);
	int m = tar.size();
	vector<vi> vg(n, vi(m));
	REP(i, n)REP(j, m){
		const S s = S(g[i], tar[j]);
		if(!sig(norm(s.dir())) || (g.contains((g[i]+tar[j])*.5) && [&](){
			REP(k, n)if(intersect(g.edge(k), s) == TRUE)
				return false;
			return true;
		}())) vg[i][j] = 1;
	}
	return vg;
}


int main(){
	ios::sync_with_stdio(false);
	while(cin >> n, n){
		vector<G> poly(n);
		REP(i, n){
			int x;
			cin >> x;
			poly[i].resize(x);
			REP(j, x) cin >> poly[i][j];
		}
		P s, t;
		cin >> s >> t;
		L l;
		cin >> l;
		int pccw = ccw(l[0], l[1], s);
		vector<G> tar;
		if(![&](){
			REP(i, n){
				if(pccw != ccw(l[0], l[1], poly[i][0]))
					REP(j, poly[i].size()) poly[i][j] = reflect(poly[i][j], l);
				int f = !!poly[i].contains(s) + !!poly[i].contains(t);
				if(f == 1) return 0;
				if(f == 2) tar.push_back(poly[i]);
			}
//			cout << poly[0] << poly[1] << s << endl << t << endl << l << endl;
			if(tar.size() != 2) return 0;
			vector<P> p;
			p.push_back(s);
			p.push_back(t);
			FOR(it, tar[0]) p.push_back(*it);
			FOR(it, tar[1]) p.push_back(*it);
			n = p.size();
			vector<vector<R>> g(n, vector<R>(n, INF));
			REP(i, n) g[i][i] = 0;
			REP(i, n)REP(j, i){
				S s(p[i], p[j]);
				if([](const vector<G> &tar, const S &s){
					vector<P> p;
					REP(k, 2){
						const G &t = tar[k];
						REP(i, t.size()){
							const auto & e = t.edge(i);
							if(!sig(outp(e.dir(), s.dir()))) continue;
							int f = intersect(e, s);
							if(f == TRUE) return 0;
							if(f == BORDER) p.push_back(crosspoint(e, s));
						}
					}
					sort(ALL(p));UNIQUE(p);
					REP(i, (int)p.size() - 1){
						const P q = (p[i] + p[i+1]) * .5;
						if(!tar[0].contains(q) || !tar[1].contains(q)) return 0;
					}
					return 1;
				}(tar, s)) g[i][j] = g[j][i] = abs(s.dir());
			}
			REP(k, n)REP(i, n)REP(j, n) g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
			if(g[0][1] > INF - EPS) return 0;
			printf("%.14f\n", g[0][1]);
			return 1;
		}()) puts("impossible");
	}
	return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 1508
final_rank: 6

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-8;
const double INF=1e77;

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	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); }
	point operator/(double c)const{ return point(x/c,y/c); }
	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; }

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

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

typedef vector<point> polygon;

point proj(const point &p,const line &L){ 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);
}

bool cover(const polygon &F,const point &p){
	int n=F.size();
	bool res=false;
	rep(i,n){
		point v1=F[i]-p,v2=F[(i+1)%n]-p;
		if(v1.y>v2.y) swap(v1,v2);
		if(v1.y<EPS && EPS<v2.y && cross(v1,v2)>EPS) res=!res;
		if(abs(cross(v1,v2))<EPS && dot(v1,v2)<EPS) return true;
	}
	return res;
}

bool cover(const polygon &F,const segment &S){
	int n=F.size();
	vector<point> P;
	P.push_back(S.a);
	P.push_back(S.b);
	rep(i,n){
		segment T(F[i],F[(i+1)%n]);
		if(intersect(S,T)) P.push_back(get_intersect(S,T));
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	int m=P.size();
	rep(i,m-1){
		point c=(P[i]+P[i+1])/2;
		if(!cover(F,c)) return false;
	}
	return true;
}

// reflection with line L
point ref(const point &p,const line &L){ return p+2.0*(proj(p,L)-p); }

bool is_passable(const point &s,const point &g,const polygon &F1,const polygon &F2,const line &L){
	return cover(F1,segment(s,g)) && cover(F2,segment(ref(s,L),ref(g,L)));
}

void solve(const polygon &F1,const polygon &F2,const point &s1,const point &s2,const point &g1,const point &g2,const line &L){
	int m1=F1.size(),m2=F2.size();
	vector<point> V; // vertices of graph
	V.push_back(s1);
	V.push_back(g1);
	rep(i,m1) V.push_back(F1[i]);
	rep(j,m2) V.push_back(ref(F2[j],L));
	rep(i,m1) rep(j,m2) {
		segment S1(F1[i],F1[(i+1)%m1]);
		segment S2(ref(F2[j],L),ref(F2[(j+1)%m2],L));
		if(intersect(S1,S2)) V.push_back(get_intersect(S1,S2));
	}

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

		if(d_now>d[u]+EPS) continue;
		if(u==1){ printf("%.9f\n",d_now); return; }

		rep(v,n){
			point p=V[u],q=V[v];
			double cost=abs(q-p);
			if(d[v]>d[u]+cost+EPS && is_passable(p,q,F1,F2,L)){
				d[v]=d[u]+cost;
				Q.push(make_pair(-d[v],v));
			}
		}
	}

	puts("impossible");
	return;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		polygon F[100];
		rep(i,n){
			int m; scanf("%d",&m);
			F[i].resize(m);
			rep(j,m) scanf("%lf%lf",&F[i][j].x,&F[i][j].y);
		}
		point s1,g1; scanf("%lf%lf%lf%lf",&s1.x,&s1.y,&g1.x,&g1.y);
		line L; scanf("%lf%lf%lf%lf",&L.a.x,&L.a.y,&L.b.x,&L.b.y);

		point s2=ref(s1,L);
		point g2=ref(g1,L);

		int is1=-1,ig1=-1,is2=-1,ig2=-1;
		rep(i,n){
			if(cover(F[i],s1)) is1=i;
			if(cover(F[i],g1)) ig1=i;
			if(cover(F[i],s2)) is2=i;
			if(cover(F[i],g2)) ig2=i;
		}

		if(is2==-1 || ig2==-1 || is2!=ig2){ puts("impossible"); continue; }

		solve(F[is1],F[is2],s1,s2,g1,g2,L);
	}

	return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 1132
final_rank: 3

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

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

using namespace std;

const double EPS=1e-8;
const double INF=1e77;

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	point &operator+=(const point &a){ x+=a.x; y+=a.y; return *this; }
	point &operator-=(const point &a){ x-=a.x; y-=a.y; return *this; }
	point &operator*=(double c){ x*=c; y*=c; return *this; }
	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); }
	point operator/(double c)const{ return point(x/c,y/c); }
	point operator-()const{ return point(-x,-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; }
	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; }

struct line{
	point a,b;
	line(){}
	line(const point &a,const point &b):a(a),b(b){}
	bool operator==(const line &L)const{ return abs(cross(b-a,L.b-L.a))<EPS && abs(cross(L.a-a,L.b-a))<EPS; }
};

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

typedef vector<point> polygon;

point proj(const point &p,const line &L){ 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);
}

bool cover(const polygon &F,const point &p){
	int n=F.size();
	bool res=false;
	rep(i,n){
		point v1=F[i]-p,v2=F[(i+1)%n]-p;
		if(v1.y>v2.y) swap(v1,v2);
		if(v1.y<EPS && EPS<v2.y && cross(v1,v2)>EPS) res=!res;
		if(abs(cross(v1,v2))<EPS && dot(v1,v2)<EPS) return true;
	}
	return res;
}

bool cover(const polygon &F,const segment &S){
	int n=F.size();
	vector<point> P;
	P.push_back(S.a);
	P.push_back(S.b);
	rep(i,n){
		segment T(F[i],F[(i+1)%n]);
		if(intersect(S,T)) P.push_back(get_intersect(S,T));
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	int m=P.size();
	rep(i,m-1){
		point c=(P[i]+P[i+1])/2;
		if(!cover(F,c)) return false;
	}
	return true;
}

// reflection with line L
point ref(const point &p,const line &L){ return p+2.0*(proj(p,L)-p); }

bool is_passable(const point &s,const point &g,const polygon &F1,const polygon &F2,const line &L){
	return cover(F1,segment(s,g)) && cover(F2,segment(ref(s,L),ref(g,L)));
}

void solve(const polygon &F1,const polygon &F2,const point &s1,const point &s2,const point &g1,const point &g2,const line &L){
	int m1=F1.size(),m2=F2.size();
	vector<point> V; // vertices of graph
	V.push_back(s1);
	V.push_back(g1);
	rep(i,m1) V.push_back(F1[i]);
	rep(j,m2) V.push_back(ref(F2[j],L));
	rep(i,m1) rep(j,m2) {
		segment S1(F1[i],F1[(i+1)%m1]);
		segment S2(ref(F2[j],L),ref(F2[(j+1)%m2],L));
		if(intersect(S1,S2)) V.push_back(get_intersect(S1,S2));
	}

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

		if(d_now>d[u]+EPS) continue;
		if(u==1){ printf("%.9f\n",d_now); return; }

		rep(v,n){
			point p=V[u],q=V[v];
			double cost=abs(q-p);
			if(d[v]>d[u]+cost+EPS && is_passable(p,q,F1,F2,L)){
				d[v]=d[u]+cost;
				Q.push(make_pair(-d[v],v));
			}
		}
	}

	puts("impossible");
	return;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		polygon F[100];
		rep(i,n){
			int m; scanf("%d",&m);
			F[i].resize(m);
			rep(j,m) scanf("%lf%lf",&F[i][j].x,&F[i][j].y);
		}
		point s1,g1; scanf("%lf%lf%lf%lf",&s1.x,&s1.y,&g1.x,&g1.y);
		line L; scanf("%lf%lf%lf%lf",&L.a.x,&L.a.y,&L.b.x,&L.b.y);

		point s2=ref(s1,L);
		point g2=ref(g1,L);

		int is1=-1,ig1=-1,is2=-1,ig2=-1;
		rep(i,n){
			if(cover(F[i],s1)) is1=i;
			if(cover(F[i],g1)) ig1=i;
			if(cover(F[i],s2)) is2=i;
			if(cover(F[i],g2)) ig2=i;
		}
		assert(is1!=-1);
		assert(ig1!=-1);
		assert(is1==ig1);

		if(is2==-1 || ig2==-1 || is2!=ig2){ puts("impossible"); continue; }

		solve(F[is1],F[is2],s1,s2,g1,g2,L);
	}

	return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 1132
final_rank: 5