Problem:
Problem E:
Alice and Bomb
Alice and Bob were in love with each other, but they hate each other now.
One day, Alice found a bag. It looks like a bag that Bob had used when they go on a date.
Suddenly Alice heard tick-tack sound. Alice intuitively thought that Bob is to kill her with a
bomb. Fortunately, the bomb has not exploded yet, and there may be a little time remained to
hide behind the buildings.
The appearance of the ACM city can be viewed as an infinite plane and each building forms a
polygon. Alice is considered as a point and the bomb blast may reach Alice if the line segment
which connects Alice and the bomb does not intersect an interior position of any building.
Assume that the speed of bomb blast is infinite; when the bomb explodes, its blast wave will
reach anywhere immediately, unless the bomb blast is interrupted by some buildings.
The figure below shows the example of the bomb explosion. Left figure shows the bomb and the
buildings(the polygons filled with black). Right figure shows the area(colored with gray) which
is under the effect of blast wave after the bomb explosion.
Figure 6: The example of the bomb explosion
Note that even if the line segment connecting Alice and the bomb touches a border of a building,
bomb blast still can blow off Alice. Since Alice wants to escape early, she wants to minimize the
length she runs in order to make herself hidden by the building.
Your task is to write a program which reads the positions of Alice, the bomb and the buildings
and calculate the minimum distance required for Alice to run and hide behind the building.
Input
The input contains multiple test cases. Each test case has the following format:
N
bx by
m
1
x
1,1
y
1,1
...
x
1,
m
1
y
1,
m
1
.
.
.
m
N
x
N
,1
y
N
,1
...
x
N
,
m
N
y
N
,
m
N
The first line of each test case contains an integer
N
(1 ≤
N
≤ 100), which denotes the number
of buildings. In the second line, there are two integers
bx
and
by
(-10000 ≤
bx
,
by
≤ 10000),
which means the location of the bomb. Then,
N
lines follows, indicating the information of the
buildings.
The information of building is given as a polygon which consists of points. For each line, it has
an integer
m
i
(3 ≤
m
i
≤ 100, ∑
N
i
=1
m
i
≤ 500) meaning the number of points the polygon has,
and then
m
i
pairs of integers
x
i,j
,
y
i,j
follow providing the x and y coordinate of the point.
You can assume that
the polygon does not have self-intersections.
any two polygons do not have a common point.
the set of points is given in the counter-clockwise order.
the initial positions of Alice and bomb will not by located inside the polygon.
there are no bomb on the any extended lines of the given polygon’s segment.
Alice is initially located at (0, 0). It is possible that Alice is located at the boundary of a
polygon.
N = 0 denotes the end of the input. You may not process this as a test case.
Output
For each test case, output one line which consists of the minimum distance required for Alice to
run and hide behin
...(truncated)

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
//#define Alex std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
//#define int long long
//#define double long double
//#define L(i,a,b) for(int i = a;i <= b;i++)
//#define R(i,a,b) for(int i = a;i >= b;i--)
using namespace std;
//const int mod = 1e9 + 7;
const int QAQ = 0;
//const double pi = std::acos(-1.0);


typedef long long LL;
typedef double LD;
typedef pair <int, int> pii;
#define cp const point &
const LD eps = 1e-7;
const LD large = 1e5;
int sgn (LD x) { return x > eps ? 1 : (x < -eps ? -1 : 0); }
LD sqr (LD x) { return x * x; }

struct point {
    LD x, y;
    point () {}
    point (LD xx, LD yy) { x = xx,y = yy; }
    point operator + (cp a) const { return {x + a.x, y + a.y}; }
    point operator - (cp a) const { return {x - a.x, y - a.y}; }
    point operator * (LD a) const { return {x * a, y * a}; }
    point operator / (LD a) const { return {x / a, y / a}; }
    bool operator != (cp a) const { return sgn(x - a.x) || sgn(y - a.y);}
    bool operator == (cp a) const { return !sgn(x - a.x) && !sgn(y - a.y); }
    bool operator < (cp a) const 
    {
        int s = sgn(x - a.x);
        if (s) return s < 0;
        return sgn(y - a.y) <0;
    }
    void read () { cin >> x >> y; }
};

LD det (cp a, cp b) { return a.x * b.y - b.x * a.y; }
LD dot (cp a, cp b) { return a.x * b.x + a.y * b.y; }
LD dis (cp a, cp b) { return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)); }

#define cl const line &

struct line{
    point s,t;
    line () {}
    line (cp ss, cp tt) { s = ss, t = tt; }
};

    inline int sgn (cp a) {return sgn(a.y) >0 || (sgn(a.y) == 0 && sgn(a.x) > 0) ? 1 :- 1; }
    inline bool two_side(cp a,cp b,cl c) { return sgn (det(a - c.s, c.t - c.s)) * sgn (det (b - c.s, c.t - c.s)) < 0;}
    inline bool turn_left (cp a,cp b,cp c) { return sgn(det(b - a, c-a)) >= 0;}
    inline bool turn_left_strict (cp a, cp b, cp c) { return sgn(det(b - a, c-a)) > 0;}

    inline bool point_on_segment (cp a,cl b) { return sgn(det(a - b.s,b.t - b.s)) == 0 && sgn(dot(b.s - a, b.t - a)) <= 0;}

    inline bool inter_judge(cl a,cl b) 
	{
        if (point_on_segment(b.s,a) || point_on_segment(b.t,a)) return true;
        if (point_on_segment(a.s,b) || point_on_segment(a.t,b)) return true;
        return two_side(a.s, a.t , b) && two_side(b.s, b.t, a);
    }

    inline bool inter_judge_strict(cl a, cl b) { return two_side(a.s, a.t, b) && two_side(b.s, b.t, a);}
    
    inline point proj_to_line(cp a, cl b) 
	{
        point st = b.t - b.s;
        return b.s + st * (dot(a - b.s, st) / dot(st, st));
    }

    inline point line_inter (cl a, cl b) 
	{
        LD s1 = det(a.t - a.s, b.s - a.s);
        LD s2 = det(a.t - a.s, b.t - a.s);
        return (b.s * s2 - b.t * s1) / (s2 - s1);
    }

    inline bool point_in_polygon (cp p, const vector <point> & po) 
	{
        int n = (int) po.size (); 
		int cnt = 0;
        for (int i = 0; i < n; ++i) 
		{
            point a = po[i], b= po[(i + 1) % n];
            if (point_on_segment(p, {a, b})) return true;
            int x= sgn (det(p - a,b - a));
            int y = sgn (a.y - p.y);
            int z = sgn (b.y - p.y);
            if (x > 0 && y <= 0 && z > 0) ++cnt;
            if (x < 0 && z <= 0 && y > 0) --cnt; 
		}
        return cnt != 0; 
	}

inline bool in_polygon(const vector <point> &p, cp u, cp v) 
{
    for(int i = 0;i < (int)p.size();i++) 
	{
        int j = (i + 1) % (int) p.size(),k = (i + 2) % (int) p.size();
        cp ii = p[i],jj = p[j],kk = p[k];
        if(inter_judge_strict({u, v}, {ii, jj})) return false;
        if (point_on_segment (jj,{u, v})) 
	    {
            bool good = true, left = turn_left(ii,jj,kk);
            for (auto x : {u, v}) 
		    {
                if (left) 
		        {
                    good &= turn_left(ii, jj, x) && turn_left(jj, kk, x);
                }else 
			    {
                    good &= (!(turn_left_strict(jj, x, kk) && turn_left_strict(jj, ii, x)));
                }
            }
            if (!good) return 0;
        }
    }
    return 1;
}



const point Z(0, 0);

int n;
vector < vector <point> > p, q;
vector < vector <int> > r;
map <point, int> id;
vector <vector < pair <int, LD> > > E;
int cnt;

void init() 
{
    p.clear(); 
	q.clear(); 
	r.clear();
    id.clear();
    E.clear(); 
	E.push_back({});
    cnt = 0;
}

void get_id(point x) 
{
    if(id.count(x))
    {
	}
    else 
	{
        id[x] = ++cnt;
        E.push_back({});
    }
}

bool check_good(cp u, cp v) 
{
    for (int i = 0; i < n; i++) 
	{
        if (!in_polygon(q[i], u, v)) 
		{
            return false;
        }
    }
    return true;
}

void add (int u, int v, LD w) 
{
    E[u].push_back ({v,w});
    if (v != 0) E[v].push_back ({u,w});
}


inline LD dij(int s,int t) 
{
    vector<LD> Dis (cnt + 1,1e18);
    Dis[s] = 0;
    priority_queue<pair<LD,int>, vector<pair<LD, int> >, greater<pair<LD,int> > > pq;
    pq.push({LD(0),s});
    while(!pq.empty()) 
	{
        LD d;
		int x;
        std::tie(d,x) = pq.top();
		pq.pop();
        if (d != Dis[x]) continue;
        if (x == t) return d;
        int v;
		LD w;
        for(auto pp : E[x]) 
		{
            std :: tie(v, w) = pp;
            if(Dis[v] > Dis[x] + w) 
			{
                Dis[v] = Dis[x] + w;
                pq.push({Dis[v],v});
            }
        }
    }
    return 1e18l;
}

inline void work() 
{
    init();
    p.resize(n);
    q.resize(n);
    r.resize(n);
    point A = Z;
    point B;
    B.read();
    for(int i = 0; i < n; i++) 
	{
        int m; 
		cin >> m;
        while(m -- ) 
		{
            point a;
            a.read();
            p[i].push_back(a);
        }
        q[i] = p[i];
        reverse(q[i].begin(), q[i].end());
    }
    if(!check_good(A, B)) 
	{ 
	    puts ("0.000000000");
		return;
	}
    for (int i = 0; i < n; i++) 
	{
        auto &po = p[i];
        r[i].resize(po.size());
        for (int j = 0; j < (int) po.size(); j++) 
		{
        auto &u = po[j],&v=po[(j + 1) % po.size()];
        auto w = (u + v) / 2;
        if(! check_good(B, w)) 
		{
            r[i][j] = 1;
            r[i][(j+1) % po.size()] = 1;
        }
        }
    }
    get_id(A);
    for(int i = 0; i < n; i++) 
	{
        auto &po = p[i];
        for(auto &u : po) 
		{
        get_id(u);
        if(check_good(A, u)) 
		{
            add(id[A], id[u], dis(A,u));
        }
        }
        for(int j = 0; j < (int) po.size(); j++) 
		if(r[i][j]) 
		{
		    add(id[po[j]],0,0);
		}
    }
    
    for (int i = 0; i < n; i++) 
	{
        auto &po = p[i];
        for (int j = 0; j < (int) po.size(); j++) {
        auto &u = po[j];
        for (int k = i; k < n; k++) 
		{
        auto &op = p[k];
        for (int l = (i == k ? j + 1: 0); l < (int) op.size(); l++) 
		{
            auto &v = op[l];
            if (check_good(u, v)) add(id[u], id[v], dis(u,v));
        }
        }
        }
    }
    
    for (int i = 0; i < n; i++) 
	{
        auto &po = p[i];
        for (int j = 0; j < (int) po.size(); j++) {
        auto &u = po[j];
        for (int k = 0; k < n; k++) {
        auto &op = p[k];
        for (int l = 0; l < (int) op.size(); l++) 
		if(r[k][l]) {
            auto &v = op[l];
            auto proj = proj_to_line(u, {B, v});
        if (!point_on_segment (proj, {B, v}) && sgn(dot(u - v, v - B)) > 0 && check_good(u, proj)) {add(id[u], 0, dis(u, proj));}
        }
        }}
    }
    for (int k = 0; k < n; k++) 
	{
        auto &op = p[k];
        for (int l = 0; l < (int) op.size(); l++) 
		if (r[k][l]) 
		{
            auto &v = op[l];
            auto proj = proj_to_line(A, {B, v});
            if (! point_on_segment (proj, {B, v}) && sgn(dot(A - v, v - B)) >0 && check_good(A, proj)) 
			{ add(id[A],0, dis(A, proj));}
        }
    }
    printf("%.9lf\n", dij(id[A],0));
}

inline void Fre() {	int liujiahui = 142857; }

signed main() 
{
//	Alex;
	Fre();
	int _;
	_ = 1;
//	std::cin>>_;
	while(_--)
	{
	}
	while("gh" == "gh")
	{
		std::cin>>n;
		if(n == 0) break;
		work();
	}
    return QAQ;
}
accuracy: 1
time_ms: 1320
memory_kb: 7424
final_rank: 12

code_snippet: #include "bits/stdc++.h"

#define all(x)   x.begin(), x.end()
#define NL       std::cout << '\n'

using lnt = long long;

const int inf = 0x3f3f3f3f;
const lnt linf = 1ll << 61;

using db = long double; const db eps = 1e-7;
int sgn(db x) { return (x < -eps ? -1 : x > eps); }

struct Pt { db x, y; };
std::istream& operator>>(std::istream& is, Pt &p) {
  int x, y; std::cin >> x >> y;
  p.x = x; p.y = y; return is;
}
std::ostream& operator<<(std::ostream& os, Pt p) {
  return os << "(" << p.x << "," << p.y << ")";
}

Pt operator-(Pt a, Pt b) { return { a.x - b.x, a.y - b.y }; }
Pt operator+(Pt a, Pt b) { return { a.x + b.x, a.y + b.y }; }
Pt operator*(Pt a, db x) { return { a.x * x, a.y * x }; }
Pt operator/(Pt a, db x) { return { a.x / x, a.y / x }; }
db dot(Pt a, Pt b) { return a.x * b.x + a.y * b.y; }
db det(Pt a, Pt b) { return a.x * b.y - a.y * b.x; }
bool operator==(Pt a, Pt b) { return !sgn(dot(a-b, a-b)); }
bool operator!=(Pt a, Pt b) { return sgn(dot(a-b, a-b)); }
bool operator<(Pt a, Pt b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }
db dis2(Pt a, Pt b) { return dot(a-b, a-b); }
db dis(Pt a, Pt b) { return std::sqrt(dis2(a, b)); }
int side(Pt a, Pt b, Pt x) { return sgn(det(b-a, x-a)); }
Pt rot90(Pt a) { return {-a.y, a.x}; }
Pt rot(Pt a, db t) {
  return { a.x * std::cos(t) - a.y * std::sin(t)
         , a.x * std::sin(t) + a.y * std::cos(t) };
}
Pt unit(Pt a) {
  db d = dis(a, {0, 0});
  return sgn(d) ? a/d : Pt{0, 0};
}


struct Line { Pt s, t; };

Pt intersect(Line a, Line b) {
  db v = det(a.t - a.s, b.s - a.s);
  db u = det(a.t - a.s, b.t - a.s);
  return (b.s * u - b.t * v) / (u - v);
}
bool para(Line a, Line b) {
  return !sgn(det(a.t - a.s, b.t - b.s));
}

bool ptOnSeg(Pt x, Line v) {
  if (v.s == v.t) { return sgn(dis2(v.s, x)) == 0; }
  return sgn(det(v.s - x, v.t - x)) == 0
      && sgn(dot(v.s - x, v.t - x)) <= 0;
}

bool ptOnSeg_strict(Pt x, Line v) {
  if (v.s == v.t) { return sgn(dis2(v.s, x)) == 0; }
  return sgn(det(v.s - x, v.t - x)) == 0
      && sgn(dot(v.s - x, v.t - x)) < 0;
}

bool segInter(Line a, Line b) {
  if (sgn(det(b.s-a.s, a.t-a.s)) * sgn(det(b.t-a.s, a.t-a.s)) == -1
   && sgn(det(a.s-b.s, b.t-b.s)) * sgn(det(a.t-b.s, b.t-b.s)) == -1) {
    return true;
  }
  return false;
}

bool ptInPoly(Pt p, std::vector<Pt> &v) {
  int cnt = 0;
  for (int i = v.size() - 1, j = 0; j < v.size() - 2; i = j++) {
    if (ptOnSeg(p, {v[i], v[j]})) { return true; }
    int x = sgn(det(p - v[i], v[j] - v[i]));
    int y = sgn(v[i].y - p.y);
    int z = sgn(v[j].y - p.y);
    if (x > 0 && y <= 0 && z > 0) { ++cnt; }
    if (x < 0 && z <= 0 && y > 0) { --cnt; }
  }
  return cnt != 0;
}


Pt projection(Pt p, Line l) {
  Pt v = l.t - l.s;
  return l.s + v * (dot(p - l.s, v) / dot(v, v));
}

bool segInPoly(Line s, std::vector<Pt> &v) {
  const int n = v.size();
  for (int i = 0; i < n - 2; ++i) {
    const Pt a = v[i], b = v[(i+1)], c = v[(i+2)];
    if (segInter(s, {a, b})) { return false; }
    if (ptOnSeg_strict(s.s, {a, b}) && side(a, b, s.t) < 0) { return false; }
    if (ptOnSeg_strict(s.t, {a, b}) && side(a, b, s.s) < 0) { return false; }
    if (ptOnSeg(b, s)) {
      bool ok = true, acute = side(a, b, c) > 0;
      for (auto x : {s.s, s.t}) {
        if (acute) {
          ok &= side(a, b, x) >= 0 && side(b, c, x) >= 0;
        } else {
          ok &= side(a, b, x) >= 0 || side(b, c, x) >= 0;
        }
      }
      if (!ok) { return false; }
    }
  }
  return true;
}

int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int n;
  const Pt alice = {0, 0};
  while (std::cin >> n && n) {
    Pt bomb; std::cin >> bomb;
    std::vector<std::vector<Pt>> poly(n);
    std::vector<std::vector<Pt>> rpoly(n);
    for (int i = 0; i < n; ++i) {
      int k; std::cin >> k;
      poly[i].resize(k);
      for (int j = 0; j < k; ++j) {
        std::cin >> poly[i][j];
      }
      rpoly[i] = poly[i];
      std::reverse(all(rpoly[i]));
      poly[i].emplace_back(poly[i][0]);   poly[i].emplace_back(poly[i][1]);
      rpoly[i].emplace_back(rpoly[i][0]); rpoly[i].emplace_back(rpoly[i][1]);
    }


    auto visible = [&](Pt u, Pt v) {
      for (int i = 0; i < n; ++i) {
        if (!segInPoly({u, v}, rpoly[i])) { return false; }
      }
      return true;
    };

    auto alive = [&](Pt u) {
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < poly[j].size() - 2; ++k) {
          Pt a = poly[j][k], b = poly[j][k+1], c = poly[j][k+2];
          if (segInter({a, b}, {bomb, u})) { return true; }
          if (!sgn(det(u - bomb, a - bomb))
              && sgn(dot(bomb - u, a - u)) > 0
              && sgn(dot(u - bomb, a - bomb)) >= 0) { return true; }
          if ((b == u) && (side(bomb, u, a) == side(bomb, u, c))) { return true; }
        }
      }
      return false;
    };

    if (!visible(bomb, alice)) {
      std::cout << "0"; NL;
      continue;
    }

    std::vector<Pt> vt({alice});
    for (int i = 0; i < n; ++i) {
      for (auto x : poly[i]) {
        vt.emplace_back(x);
      }
    }

    std::vector<Line> ls;

    std::sort(vt.begin() + 1, vt.end());
    vt.erase(std::unique(all(vt)), vt.end());

    for (auto x : vt) {
      if (alive(x)) {
        ls.push_back({bomb, x});
      }
    }


    std::vector<Pt> v3;
    for (const auto &l : ls) {
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < poly[i].size() - 2; ++j) {
          if (side(l.s, l.t, poly[i][j]) * side(l.s, l.t, poly[i][j+1]) != -1) { continue; }
          Pt inter = intersect(l, {poly[i][j], poly[i][j+1]});
          if (alive(inter)) { v3.emplace_back(inter); }
        }
      }
    }

    std::sort(all(v3));
    v3.erase(std::unique(all(v3)), v3.end());

    db ret = inf;
    std::vector<db> d(vt.size(), inf);
    std::priority_queue<std::pair<db, int>, std::vector<std::pair<db, int>>, std::greater<>> q;
    d[0] = 0;
    q.emplace(0, 0);
    while (!q.empty()) {
      auto _ = q.top(); q.pop();
      auto ddis = _.first; auto u = _.second;
      if (ret < ddis) { break; }
      if (d[u] < ddis) { continue; }
      if (alive(vt[u])) { ret = ddis; break; }
      for (auto l : ls) {
        Pt proj = projection(vt[u], l);
        if (visible(proj, vt[u]) && alive(proj)) { ret = std::min(ret, ddis + dis(proj, vt[u])); }
      }
      for (auto x : v3) {
        if (visible(x, vt[u])) {  ret = std::min(ret, ddis + dis(x, vt[u])); }
      }
      for (int v = 0; v < vt.size(); ++v) {
        db w = dis(vt[v], vt[u]);
        if (w + ddis >= d[v] || !visible(vt[v], vt[u])) { continue; }
        d[v] = w + ddis;
        q.emplace(d[v], v);
      }
    }
    std::cout << std::fixed << std::setprecision(8);
    std::cout << ret; NL;
  }

  return 0;
}
accuracy: 1
time_ms: 4110
memory_kb: 3736
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double LD;
typedef pair <int, int> pii;
#define cp const point &
const LD eps = 1e-7;
const LD large = 1e5;
int sgn (LD x) { return x > eps ? 1 : (x < -eps ? -1 : 0); }
LD sqr (LD x) { return x * x; }
 
struct point {
	LD x, y;
	point () {}
	point (LD xx, LD yy) { x = xx, y = yy; }
	point operator + (cp a) const { return {x + a.x, y + a.y}; }
	point operator - (cp a) const { return {x - a.x, y - a.y}; }
	point operator * (LD a) const { return {x * a, y * a}; }
	point operator / (LD a) const { return {x / a, y / a}; }
	bool operator != (cp a) const { return sgn(x - a.x) || sgn(y - a.y); }
	bool operator == (cp a) const { return !sgn(x - a.x) && !sgn(y - a.y); }
	bool operator <  (cp a) const {
		int s = sgn(x - a.x);
		if (s) return s < 0;
		return sgn(y - a.y) < 0;
	}
	void read () { cin >> x >> y; }
};
 
LD det (cp a, cp b) { return a.x * b.y - b.x * a.y; }
LD dot (cp a, cp b) { return a.x * b.x + a.y * b.y; }
LD dis (cp a, cp b) { return sqrt (sqr(a.x - b.x) + sqr(a.y - b.y)); }
 
 
#define cl const line &
struct line {
	point s, t;
	line () {}
	line (cp ss, cp tt) { s = ss, t = tt; }
};
 
int sgn (cp a) {return sgn(a.y) > 0 || (sgn(a.y) == 0 && sgn(a.x) > 0) ? 1 : -1;}
bool two_side(cp a, cp b, cl c) {
	return sgn (det(a - c.s, c.t - c.s)) * sgn (det (b - c.s, c.t - c.s)) < 0;
}
bool turn_left (cp a, cp b, cp c) { return sgn(det(b - a, c - a)) >= 0; }
bool turn_left_strict (cp a, cp b, cp c) { return sgn(det(b - a, c - a)) > 0; }
 
bool point_on_segment(cp a, cl b) {
	return sgn (det( a - b.s, b.t - b.s)) == 0 
	&& sgn (dot (b.s - a, b.t - a)) <= 0;
}
 
bool inter_judge(cl a, cl b) {
	if (point_on_segment(b.s, a) || point_on_segment(b.t, a)) return true;
	if (point_on_segment(a.s, b) || point_on_segment(a.t, b)) return true;
	return two_side(a.s, a.t, b) && two_side(b.s, b.t, a);
}
 
bool inter_judge_strict(cl a, cl b) {
	return two_side(a.s, a.t, b) && two_side(b.s, b.t, a);
}

point proj_to_line(cp a, cl b) {
	point st = b.t - b.s;
	return b.s + st * (dot(a - b.s, st) / dot(st, st));
}

point line_inter(cl a, cl b) {
	LD s1 = det(a.t - a.s, b.s - a.s);
	LD s2 = det(a.t - a.s, b.t - a.s);
	return (b.s * s2 - b.t * s1) / (s2 - s1);
}

bool point_in_polygon (cp p, const vector <point> & po) {
	int n = (int) po.size (); int cnt = 0;
	for (int i = 0; i < n; ++i) {
		point a = po[i], b = po[(i + 1) % n];
		if (point_on_segment (p, {a, b})) return true;
		int x = sgn (det(p - a, b - a));
		int y = sgn (a.y - p.y);
		int z = sgn (b.y - p.y);
		if (x > 0 && y <= 0 && z > 0) ++cnt;
		if (x < 0 && z <= 0 && y > 0) --cnt; }
	return cnt != 0; }

bool in_polygon(const vector <point> &p, cp u, cp v) {
	for (int i = 0; i < (int) p.size(); i++) {
		int j = (i + 1) % (int) p.size(), k = (i + 2) % (int) p.size();
		cp ii = p[i], jj = p[j], kk = p[k];
		if (inter_judge_strict({u, v}, {ii, jj})) return false;
		if (point_on_segment(jj, {u, v})) {
			bool good = true, left = turn_left(ii, jj, kk);
			for (auto x : {u, v}) {
				if (left) {
					good &= turn_left(ii, jj, x) && turn_left(jj, kk, x);
				} else {
					good &= !(turn_left_strict(jj, x, kk) && turn_left_strict(jj, ii, x));
				}
			}
			if (!good) return 0;
		}
	}
	return 1;
}

const point Z(0, 0);

int n;
vector < vector <point> > p, q;
vector < vector <int> > r;
map <point, int> id;
vector <vector < pair <int, LD> > > E;
int cnt;

void init() {
	p.clear(); q.clear(); r.clear();
	id.clear();
	E.clear(); E.push_back({});
	cnt = 0;
}

void get_id (point x) {
	if (id.count(x));
	else {
		id[x] = ++cnt;
		E.push_back({});
	}
}

bool check_good(cp u, cp v) {
	for (int i = 0; i < n; i++) {
		if (!in_polygon(q[i], u, v)) {
			return false;
		}
	}
	return true;
}

void add (int u, int v, LD w) {
	E[u].push_back({v, w});
	if (v != 0) E[v].push_back({u, w});
}


LD dij (int s, int t) {
	vector <LD> Dis (cnt + 1, 1e18);
	Dis[s] = 0;
	priority_queue < pair <LD, int>, vector < pair <LD, int>>, greater < pair <LD, int>>> pq;
	pq.push({LD(0), s});
	while (!pq.empty()) {
		auto [d, x] = pq.top(); pq.pop();
		if (d != Dis[x]) continue; 
		if (x == t) return d;
		for (auto [v, w] : E[x]) {
			if (Dis[v] > Dis[x] + w) {
				Dis[v] = Dis[x] + w;
				pq.push({Dis[v], v});
			}
		}
	}
	return 1e18; // ??
}

void work() {
	init();
	p.resize(n);
	q.resize(n);
	r.resize(n);
	point A = Z;
	point B;
	B.read();
	for (int i = 0; i < n; i++) {
		int m; cin >> m;
		while (m--) {
			point a;
			a.read();
			p[i].push_back(a);
		}
		q[i] = p[i];
		reverse(q[i].begin(), q[i].end());
	}
	if (!check_good(A, B)) {
		puts ("0.0");
		return;
	}
	for (int i = 0; i < n; i++) {
		auto &po = p[i];
		r[i].resize(po.size());
		for (int j = 0; j < (int) po.size(); j++) {
			auto &u = po[j], &v = po[(j + 1) % po.size()];
			auto w = (u + v) / 2;
			if (!check_good(B, w)) {
				r[i][j] = 1;
				r[i][(j + 1) % po.size()] = 1;
			}
		}
	}
	get_id(A);
	for (int i = 0; i < n; i++) {
		auto &po = p[i];
		for (auto &u : po) {
			get_id(u);
			if (check_good(A, u)) {
				add(id[A], id[u], dis(A, u));
			}
		}
		for (int j = 0; j < (int) po.size(); j++) if (r[i][j]) {
			add(id[po[j]], 0, 0);
		}
	}

	for (int i = 0; i < n; i++) {
		auto &po = p[i];
		for (int j = 0; j < (int) po.size(); j++) {
			auto &u = po[j];
			for (int k = i; k < n; k++) {
				auto &op = p[k];
				for (int l = (i == k ? j + 1 : 0); l < (int) op.size(); l++) {
					auto &v = op[l];
					if (check_good(u, v)) add(id[u], id[v], dis(u, v));
				}
			}
		}
	}

	for (int i = 0; i < n; i++) {
		auto &po = p[i];
		for (int j = 0; j < (int) po.size(); j++) {
			auto &u = po[j];
			for (int k = 0; k < n; k++) {
				auto &op = p[k];
				for (int l = 0; l < (int) op.size(); l++) if (r[k][l]) {
					auto &v = op[l];
					auto proj = proj_to_line(u, {B, v});
					if (!point_on_segment(proj, {B, v})
						&& sgn(dot(u - v, v - B)) > 0
						&& check_good(u, proj)) {
						add(id[u], 0, dis(u, proj));
					}
				}
			}
		}
	}
	for (int k = 0; k < n; k++) {
		auto &op = p[k];
		for (int l = 0; l < (int) op.size(); l++) if (r[k][l]) {
			auto &v = op[l];
			auto proj = proj_to_line(A, {B, v});
			if (!point_on_segment(proj, {B, v})
					&& sgn(dot(A - v, v - B)) > 0
					&& check_good(A, proj)) {
				add(id[A], 0, dis(A, proj));
			}
		}
	}
	printf("%.9lf\n", dij(id[A], 0));
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	while (cin >> n && n) work();
}
accuracy: 1
time_ms: 1830
memory_kb: 7400
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define MAX 1000005
#define INF 1e8
#define none -1145141919810
#define ls p<<1
#define rs p<<1|1
typedef pair<int,int>Pl;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll>Pll;
const ll mod=1e9+7;
typedef long double db;
const db pi=acosl(-1.0);
const db eps=1e-6;
const db g=9.8;
int sign(db a){return a<-eps?-1:a>eps;}
int cmp(db a,db b){return sign(a-b);}
struct P{
    db x,y;
    P(db x=0,db y=0):x(x),y(y){}
    P operator+(P p){return {x+p.x,y+p.y};}
    P operator-(P p){return {x-p.x,y-p.y};}
    P operator*(db d){return {x*d,y*d};}
    P operator/(db d){return{x/d,y/d};}
    bool operator<(P p){
        int c=cmp(x,p.x);
        if(c) return c==-1;
        return cmp(y,p.y)==-1;
    }
    bool operator==(P o){
        return cmp(x,o.x)==0&&cmp(y,o.y)==0;
    }
    bool operator!=(P o){
        return cmp(x,o.x)!=0||cmp(y,o.y)!=0;
    }
    int quad()const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
    db dot(P p){return x*p.x+y*p.y;}
    db det(P p){return x*p.y-y*p.x;}
    db abs1(){return sqrt(abs2());}
    db abs2(){return x*x+y*y;}
    db disTo(P p){return (*this-p).abs1();}
    db disTo2(P p){return (*this-p).abs2();}
    P rot90(){return P(-y,x);}
    P unit(){return *this/abs1();}
    P rot(db an){return {x*cos(an)-y*sin(an),x*sin(an)+y*cos(an)};}
    db alpha(){return atan2l(y,x);}
};
db cross(P p1,P p2,P p3){return (p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y);}
db crossop(P p1,P p2,P p3){return sign(cross(p1,p2,p3));}
db rad(P p1,P p2){return atan2l(p1.det(p2),p1.dot(p2));}
bool cheLL(P p1,P p2,P q1,P q2){
    db a1=cross(q1,q2,p1),a2=-cross(q1,q2,p2);
    return sign(a1+a2)!=0;
}
P isLL(P p1,P p2,P q1, P q2){
    db a1=cross(q1,q2,p1),a2=-cross(q1,q2,p2);
    return (p1*a2+p2*a1)/(a1+a2);
}
bool intersect(db l1,db r1,db l2,db r2){
    if(l1>r1) swap(l1,r1);
    if(l2>r2) swap(l2,r2);
    return !(cmp(r1,l2)==-1||cmp(r2,l1)==-1);
}
bool isSS(P p1,P p2,P q1,P q2){
    return intersect(p1.x,p2.x,q1.x,q2.x)&&intersect(p1.y,p2.y,q1.y,q2.y)&&crossop(p1,p2,q1)*crossop(p1,p2,q2)<=0&&crossop(q1,q2,p1)*crossop(q1,q2,p2)<=0;
}
bool isSS_strict(P p1,P p2,P q1,P q2){
    return crossop(p1,p2,q1)*crossop(p1,p2,q2)<0&&crossop(q1,q2,p1)*crossop(q1,q2,p2)<0;
}
bool ismiddle(db a,db b, db m){
    return sign(a-m)==0||sign(b-m)==0||(a<m)!=(b<m);
}
bool ismiddle(P a,P b,P m){
    return ismiddle(a.x,b.x,m.x)&&ismiddle(a.y,b.y,m.y);
}
bool onseg(P p1,P p2, P q){
    return crossop(p1,p2,q)==0&&ismiddle(p1,p2,q);
}
bool onseg_strict(P p1,P p2,P q){
    return crossop(p1,p2,q)==0&&sign((q-p1).dot(p1-p2))*sign((q-p2).dot(p1-p2))<0;
}
P proj(P p1,P p2,P q){
    P dir=p2-p1;
    return p1+dir*(dir.dot(q-p1)/dir.abs2());
}
P refle(P p1,P p2,P q){
    return proj(p1,p2,q)*2-q;
}
db nearest(P p1,P p2,P q){
    if(p1==p2) return p1.disTo(q);
    P h=proj(p1,p2,q);
    if(ismiddle(p1,p2,h)){
        return q.disTo(h);
    }
    return min(p1.disTo(q),p2.disTo(q));
}
db disSS(P p1,P p2,P q1,P q2){
    if(isSS(p1,p2,q1,q2)) return 0;
    return min(min(nearest(p1,p2,q1),nearest(p1,p2,q2)),min(nearest(q1,q2,p1),nearest(q1,q2,p2)));
}
bool cmp(P a,P b){
    int qa=a.quad(),qb=b.quad();
    if(qa!=qb) return qa<qb;
    else return sign(a.det(b))>0;   
}
db area(vector<P>&ps){
    db ans=0;
    int n=ps.size();
    for(int i=0;i<n;i++){
        ans+=ps[i].det(ps[(i+1)%n]);
    }
    return ans/2.0; 
}
int contain(vector<P>&ps,P p){
    int n=ps.size();
    int ret=0;
    for(int i=0;i<n;i++){
        P u=ps[i],v=ps[(i+1)%n];
        if(onseg(u,v,p)) return 1;
        if(cmp(u.y,v.y)<=0) swap(u,v);
        if(cmp(p.y,u.y)>0||cmp(p.y,v.y)<=0) continue;
        ret^=crossop(p,u,v)>0;
    }
    return ret*2;
}
vector<P>convexHull(vector<P>&ps){
    int n=ps.size();if(n<=1) return ps;
    sort(ps.begin(),ps.end());
    vector<P>qs(n*2);
    int k=0;
    for(int i=0;i<n;qs[k++]=ps[i++]){
        while(k>1&&crossop(qs[k-2],qs[k-1],ps[i])<=0) k--;
    }
    for(int i=(n-2),t=k;i>=0;qs[k++]=ps[i--]){
        while(k>t&&crossop(qs[k-2],qs[k-1],ps[i])<=0) k--;
    }
    qs.resize(k-1);
    return qs;
}
db convexDiameter(vector<P>&ps){
    int n=ps.size(); if(n<=1) return 0;
    int is=0,js=0;
    for(int i=1;i<n;i++){
        is=ps[i]<ps[is]?i:is;
        js=ps[js]<ps[i]?i:js;
    }
    db ret=ps[is].disTo(ps[js]);
    int i=is,j=js;
    do{
        if((ps[(i+1)%n]-ps[i]).det((ps[(j+1)%n]-ps[j]))>=0)  (++j)%=n;
        else (++i)%=n;
        ret=max(ret,ps[i].disTo(ps[j]));
    }while(i!=is||j!=js);
    return ret;
}
vector<P> convexCut(const vector<P>&ps,P q1,P q2){
    vector<P>qs;
    int n=ps.size();
    for(int i=0;i<n;i++){
        P p1=ps[i],p2=ps[(i+1)%n];
        int d1=crossop(q1,q2,p1),d2=crossop(q1,q2,p2);
        if(d1>=0) qs.push_back(p1);
        if(d1*d2<0) qs.push_back(isLL(p1,p2,q1,q2));
    }
    return qs;
}
vector<P>convexHullStrict(vector<P>&ps){
    int n=ps.size();if(n<=1) return ps;
    sort(ps.begin(),ps.end());
    n=unique(ps.begin(),ps.end())-ps.begin();
    vector<P>qs(n*2);
    int k=0;
    for(int i=0;i<n;qs[k++]=ps[i++]){
        while(k>1&&crossop(qs[k-2],qs[k-1],ps[i])<0) k--;
    }
    for(int i=(n-2),t=k;i>=0;qs[k++]=ps[i--]){
        while(k>t&&crossop(qs[k-2],qs[k-1],ps[i])<0) k--;
    }
    qs.resize(k-1);
    return qs;
}
int type(P o1,db r1,P o2,db r2){
    db d=o1.disTo(o2);
    if(cmp(d,r1+r2)==1) return 4;
    if(cmp(d,r1+r2)==0) return 3;
    if(cmp(d,abs(r1-r2))==1) return 2;
    if(cmp(d,abs(r1-r2))==0) return 1;
    return 0;
}
vector<P> isCL(P o,db r,P p1,P p2){ //圆和线段
    if(cmp(abs((o-p1).det(p2-p1))/p1.disTo(p2),r)>0) return {};
    db x=(p1-o).dot(p2-p1),y=(p2-p1).abs2(),d=x*x-y*((p1-o).abs2()-r*r);
    d=max(d,(db)0.0);
    P m=p1-(p2-p1)*(x/y),dr=(p2-p1)*(sqrt(d)/y);
    return {m-dr,m+dr};
}
vector<P> isCC(P o1,db r1,P o2,db r2){ //圆和圆
    db d=o1.disTo(o2);
    if(cmp(d,r1+r2)==1) return {};
    if(cmp(d,abs(r1-r2))==-1) return {};
    d=min(d,r1+r2);
    db y=(r1*r1+d*d-r2*r2)/(2*d),x=sqrt(r1*r1-y*y);
    P dr=(o2-o1).unit();
    P q1=o1+dr*y,q2=dr.rot90()*x;
    return {q1-q2,q1+q2};
}
//intanCC:-r2,tanCP r2=0
vector<pair<P,P>> tanCC(P o1,db r1,P o2,db r2){
    P d=o2-o1;
    db dr=r1-r2,d2=d.abs2(),h2=d2-dr*dr;
    if(sign(d2)==0||sign(h2)<0) return {};
    h2=max((db)0.0,h2);
    vector<pair<P,P>>ret;
    for(db sign:{-1,1}){
        P v=(d*dr+d.rot90()*sqrt(h2)*sign)/d2;
        ret.push_back({o1+v*r1,o2+v*r2});
    }
    if(sign(h2)==0) ret.pop_back();
    return ret;
}
P inCenter(P A,P B,P C){
    db a=(B-C).abs1(),b=(C-A).abs1(),c=(A-B).abs1();
    return (A*a+B*b+C*c)/(a+b+c);
}
P circumCenter(P A,P B,P C){
    P bb=B-A,cc=C-A;
    db da=bb.abs2(),dc=cc.abs2(),d=2*bb.det(cc);
    return A-P(bb.y*dc-cc.y*da,cc.x*da-bb.x*dc)/d;
}
P othroCenter(P a,P b,P c){
    P ba=b-a,ca=c-a,bc=b-c;
    db Y=ba.y*ca.y*bc.y,
    A=ca.det(ba),
    x0=(Y+ca.x*ba.y*b.x-ba.x*ca.y*c.x)/A,
    y0=-ba.x*(x0-c.x)/ba.y+ca.y;
    return {x0,y0};
}
pair<P,db> min_circle(vector<P>&ps){
    random_shuffle(ps.begin(),ps.end());
    int n=ps.size();
    P o=ps[0];db r=0;
    for(int i=1;i<n;i++){
        if(o.disTo(ps[i])>r+eps){
            o=ps[i],r=0;
            for(int j=0;j<i;j++){
                if(o.disTo(ps[j])>eps+r){
                    o=(ps[i]+ps[j])/2;
                    r=o.disTo(ps[i]);
                    for(int k=0;k<j;k++){
                        if(o.disTo(ps[k])>r+eps){
                            o=circumCenter(ps[i],ps[j],ps[k]);
                            r=o.disTo(ps[i]);                       
                        }
                    }
                }
            }
        }
    }
    return {o,r};
}
vector<P>minkowski(vector<P>ps,vector<P>qs){
    int n=ps.size(),m=qs.size();
    vector<P>s1(n),s2(m);
    for(int i=0;i<n;i++) s1[i]=ps[(i+1)%n]-ps[i];
    for(int i=0;i<m;i++) s2[i]=qs[(i+1)%m]-qs[i];
    vector<P>Q;
    Q.push_back(ps[0]+qs[0]);
    int i=0,j=0;
    while(i<n&&j<m){
        if(s1[i].det(s2[j])>=0) Q.push_back(Q.back()+s1[i++]);
        else Q.push_back(Q.back()+s2[j++]);
    }
    while(i<n) Q.push_back(Q.back()+s1[i++]);
    while(j<m) Q.push_back(Q.back()+s2[j++]);
    return Q;
}
bool inConvex(vector<P>&ps,P p){
    int n=ps.size();
    int l=0,r=n-1;
    while(l+1<r){
        int mid=(l+r)/2;
        db A=crossop(ps[0],ps[mid],p);
        db B=crossop(ps[0],ps[(mid+1)],p);
        if(A>=0&&B<=0){
            if(crossop(ps[mid],ps[mid+1],p)>=0) return true;
            return false;
        }
        else if(A<0) r=mid;
        else l=mid;
    }
    return false;
}
const int N=505;
int n,m;
vector<vector<P>>conv;
vector<P>ps;
P o;
P p0;
int tot=0;
db dis[N][N];
db ans[N];
bool ok[N];
map<int,P>mp;
void debug(P os){
    cerr << "[" << os.x << " " << os.y << "] ";
}
bool check(P a,P b){
    for(int i=0;i<n;i++){
        int ns=conv[i].size();
        for(int j=0;j<ns;j++){
            if(isSS_strict(a,b,conv[i][j],conv[i][(j+1)%ns])) return 0;
        }
    }
    return 1;
}
void sol(){
    for(int i=0;i<=tot;i++) ans[i]=1e15;
    for(int i=0;i<=tot;i++) ok[i]=false;
    for(int i=0;i<=tot;i++){
        for(int j=0;j<=tot;j++){
            dis[i][j]=1e15;
        }
    }
    assert(ps.size()==tot);
    for(int i=0;i<tot;i++){
        for(int j=0;j<tot;j++){
            if(check(ps[i],ps[j])){
                dis[i][j]=ps[i].disTo(ps[j]);
                dis[j][i]=ps[j].disTo(ps[i]);
            }
        }
    }
    int T=1;
    for(int i=0;i<n;i++){
        int ns=conv[i].size();
        for(int j=0;j<ns;j++){
            dis[T+j][T+(j+1)%ns]=conv[i][j].disTo(conv[i][(j+1)%ns]);
            dis[T+(j+1)%ns][T+j]=conv[i][j].disTo(conv[i][(j+1)%ns]);
        }
        T+=ns;
    }
    T=1;
    for(int i=0;i<n;i++){
        int ns=conv[i].size();
        for(int j=0;j<ns;j++){
            if(crossop(p0,conv[i][j],conv[i][(j+1)%ns])>0){
                ok[j+T]=true;
                ok[(j+1)%ns+T]=true;
            }
        }
        T+=ns;
    }
    queue<int>que;
    ans[0]=0;
    db ANS=1e15;
    que.push(0);
    while(!que.empty()){
        auto u=que.front();
        que.pop();
        auto x=mp[u];
        if(ok[u]){
            ANS=min(ANS,ans[u]);
            continue;
        }
        T=1;
        for(int i=0;i<n;i++){
            int ns=conv[i].size();
            for(int j=0;j<ns;j++){
                int id=T+j;
                if(cmp(dis[u][id],1e15)>=0) continue;
                if(ans[u]+dis[u][id]<ans[id]){
                    ans[id]=ans[u]+dis[u][id];
                    que.push(id);
                }
            }
            T+=ns;
        }
        T=1;
        for(int i=0;i<n;i++){
            int ns=conv[i].size();
            for(int j=0;j<ns;j++){
                int id=T+j;
                //debug(conv[i][j]);
                //cerr << id << " ";
                //cerr << ok[id] << "\n";
                if(ok[id]){
                    P a=x-conv[i][j];
                    P b=p0-conv[i][j];
                    if(sign(a.dot(b))>0) continue;
                    P h=proj(conv[i][j],p0,x);
                    //debug(a);
                    //debug(b);
                    //cerr << "\n";
                    db di=h.disTo(x);
                    //cerr << ans[u]+di << "\n";
                    if(ans[id]>ans[u]+di){
                        ans[id]=ans[u]+di;
                        que.push(id);
                    }
                }
            }
            T+=ns;
        }
    }
    //for(int i=1;i<=8;i++) cerr << ok[i] << " ";
    cout << ANS << "\n";
}
void solve(){
    while(cin >> n){
        if(n==0) break;
        cin >> p0.x >> p0.y;
        conv.clear();
        ps.clear();
        tot=0;
        tot++;
        ps.push_back(o);
        for(int i=0;i<n;i++){
            //int m;
            cin >> m;
            vector<P>cv;
            for(int j=0;j<m;j++){
                ll x,y;
                cin >> x >> y;
                P qs;
                qs.x=x;
                qs.y=y;
                mp[j+tot]=qs;
                ps.push_back(qs);
                cv.push_back(qs);
            }
            conv.push_back(cv);
            tot+=m;
        }
        if(check(o,p0)==0){
            cout << "0.00000000" << "\n";
            continue;
        }
        sol();
    }
} 
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cout << fixed << setprecision(12);
    int t=1;
    //cin >> t;
    while(t--)
    solve();
    return 0;
}
accuracy: 1
time_ms: 4020
memory_kb: 7936
final_rank: 19

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <random>
#include <array>
#include <tuple>
#include <queue>
typedef long long ll;
typedef double ld;
const ll INF = 1e17;
const int LEN = 505;
const ld TOL = 1e-7;
const ll MOD = 1'000'000'007;
int N, M, T;
bool zero(const ld& x) { return std::abs(x) < TOL; }
int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }

ld COST[LEN];
struct Info {
	int i;
	ld c;
	Info(int I = 0, ld C = 0) : i(I), c(C) {}
	bool operator < (const Info& x) const { return c > x.c; }
};
std::vector<Info> G[LEN];
std::priority_queue<Info> Q;
ld dijkstra(int v, int g) {
	for (int i = 0; i < LEN; i++) COST[i] = INF;
	Q.push({ v, 0 });
	COST[v] = 0;
	while (Q.size()) {
		Info p = Q.top(); Q.pop();
		if (p.c > COST[p.i]) continue;
		if (p.i == g) return COST[g];
		for (const Info& w : G[p.i]) {
			ld cost = p.c + w.c;
			if (COST[w.i] > cost) {
				COST[w.i] = cost;
				Q.push({ w.i, cost });
			}
		}
	}
	return COST[g];
}
struct Pos {
	ld x, y;
	int i;
	bool good;
	Pos(ld X = 0, ld Y = 0, int I = 0, bool f = 0) : x(X), y(Y), i(I), good(f) {}
	inline bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	inline Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	inline Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	inline Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	inline ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	inline ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	ld xy() const { return x * y; }
	Pos rot(ld the) { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	inline ld Euc() const { return x * x + y * y; }
	//inline ld mag() const { return sqrt(Euc()); }
	inline ld mag() const { return hypot(x, y); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	inline friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
bool cmpx(const Pos& p, const Pos& q) { return p.x == q.x ? p.y < q.y : p.x < q.x; }
bool cmpy(const Pos& p, const Pos& q) { return p.y == q.y ? p.x < q.x : p.y < q.y; }
bool cmpi(const Pos& p, const Pos& q) { return p.i < q.i; }
Polygon H[105];
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
	ld mag() const { return hypot(vy, vx); }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator * (const Line& l) const { return s * l.s; }
	ld operator / (const Line& l) const { return s / l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	ld mag() const { return s.mag(); }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
inline Line L(const Pos& s, const Pos& e) {
	ld dy, dx, c;
	dy = e.y - s.y;
	dx = s.x - e.x;
	c = dy * s.x + dx * s.y;
	return Line(Vec(dy, dx), c);
}
inline Line L(const Vec& s, const Pos& p) {
	ld c = s.vy * p.x + s.vx * p.y;
	return Line(s, c);
}
inline Line rotate(const Line& l, const Pos& p, ld the) {
	Vec s = l.s;
	ld x = -s.vx, y = s.vy;
	ld vx = -(x * cos(the) - y * sin(the));
	ld vy = x * sin(the) + y * cos(the);
	ld c = vy * p.x + vx * p.y;
	return Line(Vec(vy, vx), c);
}
inline Line rot90(const Line& l, const Pos& p) {
	Vec s = ~l.s;
	ld c = s.vy * p.x + s.vx * p.y;
	return Line(s, c);
}
inline Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
inline ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
inline ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
inline ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
inline int ccw(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = cross(d1, d2, d3);
	return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
inline int ccw(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) {
	ld ret = cross(d1, d2, d3, d4);
	return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
inline bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && (ret > 0 || zero(ret));
}
inline bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && ret > 0;
}
inline bool intersect(const Pos& s1, const Pos& s2, const Pos& d1, const Pos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	return f1 && f2;
	//bool f3 = on_seg_strong(s1, s2, d1) ||
	//	on_seg_strong(s1, s2, d2) ||
	//	on_seg_strong(d1, d2, s1) ||
	//	on_seg_strong(d1, d2, s2);
	//return (f1 && f2) || f3;
}
inline ld area(std::vector<Pos>& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % sz];
		ret += cross(O, cur, nxt);
	}
	return ret;
}
inline bool norm(std::vector<Pos>& H) { 
	if (area(H) < TOL) {
		std::reverse(H.begin(), H.end());
		return 0;
	}
	return 1;
}
inline int inner_check(const std::vector<Pos>& H, const Pos& p) {//concave
	int cnt = 0, sz = H.size();
	for (int i = 0; i < sz; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % sz];
		if (on_seg_strong(cur, nxt, p)) return 1;
		if (zero(cur.y - nxt.y)) continue;
		if (nxt.y < cur.y) std::swap(cur, nxt);
		if (nxt.y - TOL < p.y || cur.y > p.y) continue;
		cnt += ccw(cur, nxt, p) > 0;
	}
	return (cnt & 1) * 2;
}
inline int on_seg_check(const Pos& p) {
	for (int i = 0; i < N; i++) {
		int sz = H[i].size();
		for (int j = 0; j < sz; j++) {
			Pos& a = H[i][j], b = H[i][(j + 1) % sz];
			if (on_seg_strong(a, b, p)) return i;
		}
	}
	return -2;
}
inline bool meaningless(const Pos& b, const Pos& p) {
	bool r = 0, l = 0;
	for (int i = 0; i < N; i++) {
		int sz = H[i].size();
		for (int j = 0; j < sz; j++) {
			Pos cur = H[i][j], nxt = H[i][(j + 1) % sz];
			if (intersect(b, p, cur, nxt)) return 1;
			if (on_seg_weak(b, p, cur) && ccw(b, p, cur, nxt) > 0) l = 1;
			if (on_seg_weak(b, p, cur) && ccw(b, p, cur, nxt) < 0) r = 1;
			if (on_seg_weak(b, p, nxt) && ccw(b, p, nxt, cur) > 0) l = 1;
			if (on_seg_weak(b, p, nxt) && ccw(b, p, nxt, cur) < 0) r = 1;
			if (r && l) return 1;
		}
	}
	return 0;
}
inline bool blocked(const Pos& u, const Pos& v, const int& u_idx, const int& v_idx) {
	if (u_idx == v_idx) {
		int sz = H[u_idx].size();
		for (int i = 0; i < sz; i++) {
			Pos cur = H[u_idx][i], nxt = H[u_idx][(i + 1) % sz];
			if (intersect(u, v, cur, nxt)) return 1;
			if (on_seg_weak(u, v, cur)) return 1;
		}
		Pos m = (u + v) * .5;
		//std::cout << "m :  " << m << "\n";
		//std::cout << inner_check(H[u_idx], m) << "\n";
		return inner_check(H[u_idx], m) > 1;
	}
	else {
		for (int i = 0; i < N; i++) {
			int sz = H[i].size();
			for (int j = 0; j < sz; j++) {
				Pos cur = H[i][j], nxt = H[i][(j + 1) % sz];
				if (intersect(u, v, cur, nxt)) return 1;
				if (on_seg_weak(u, v, cur)) return 1;
			}
		}
		return 0;
	}
}
inline bool covered(const Pos& b, const int& h_idx, const int& p_idx) {
	bool r = 0, l = 0;
	int sz = H[h_idx].size();
	if (ccw(b, H[h_idx][p_idx], H[h_idx][(p_idx + 1) % sz]) > 0) return 1;
	if (ccw(b, H[h_idx][p_idx], H[h_idx][((p_idx - 1 + sz) % sz)]) < 0) return 1;
	Pos& p = H[h_idx][p_idx];
	for (int i = 0; i < N; i++) {
		sz = H[i].size();
		for (int j = 0; j < sz; j++) {
			Pos cur = H[i][j], nxt = H[i][(j + 1) % sz];
			if (intersect(b, p, cur, nxt)) return 1;
			if (on_seg_weak(b, p, cur) && ccw(b, p, cur, nxt) > 0) l = 1;
			if (on_seg_weak(b, p, cur) && ccw(b, p, cur, nxt) < 0) r = 1;
			if (on_seg_weak(b, p, nxt) && ccw(b, p, nxt, cur) > 0) l = 1;
			if (on_seg_weak(b, p, nxt) && ccw(b, p, nxt, cur) < 0) r = 1;
			if (r && l) return 1;
		}
	}
	return 0;
}
inline void init() {
	while (Q.size()) Q.pop();
	for (int i = 0; i < 100; i++) std::vector<Pos>().swap(H[i]);
	for (int i = 0; i < LEN; i++) std::vector<Info>().swap(G[i]);
	return;
}
ld query() {
	init();
	int goal = 0;
	Pos s, bomb;
	s = O; s.i = 1;
	std::cin >> bomb; bomb.i = -1;
	T = 1;
	int X = -1;//if Alice is located at the boundary of a polygon X = polygon.i
	for (int i = 0; i < N; i++) {
		std::cin >> M;
		H[i].resize(M);
		for (Pos& p : H[i]) std::cin >> p;
		assert(norm(H[i]));
		for (Pos& p : H[i]) p.i = ++T;
		int f = inner_check(H[i], s);
#ifdef ASSERT
		assert(f < 2);
		assert(!inner_check(H[i], bomb));
#endif
		if (f) X = i;
	}
	int f1 = 0;
	for (int i = 0; i < N; i++) {
		int sz = H[i].size();
		for (int j = 0; j < sz; j++) {
			if (covered(bomb, i, j)) H[i][j].good = 1;
			if (H[i][j].good && H[i][j] == s) f1 = 1;
		}
	}

	//std::cout << "DEBUG\n";
	//for (Pos& p : H[0]) std::cout << p << " " << p.good << "\n";
	//std::cout << "DEBUG\n";

	if (f1 || blocked(bomb, s, -1, -2)) return 0;

	Pos inx;
	Line safe, sht, seg;//safe line, short, segment
	for (int i = 0; i < N; i++) {
		int szi = H[i].size();
		for (int j = 0; j < szi; j++) {//O(500)
			Pos& p = H[i][j];
			if (p.good) {
				G[p.i].push_back(Info(goal, 0));
				safe = L(bomb, p);
				sht = rot90(safe, s);
				inx = intersection(safe, sht);
				if (!meaningless(bomb, inx)) {
					if (on_seg_weak(bomb, inx, p)) {
						inx.i = on_seg_check(inx);
						if (inx.i == X) {
							if (!blocked(s, inx, -1, inx.i) && !blocked(s, inx, X, inx.i))
								G[1].push_back(Info(goal, (s - inx).mag()));
						}
						else {
							if (!blocked(s, inx, X, inx.i))
								G[1].push_back(Info(goal, (s - inx).mag()));
						}
					}
				}

				for (int k = 0; k < N; k++) {
					int szk = H[k].size();
					for (int l = 0; l < szk; l++) {//(O(250 * 250)
						Pos& v = H[k][l];
						if (v.good) continue;

						sht = rot90(safe, v);
						inx = intersection(safe, sht);
						if (meaningless(bomb, inx)) continue;

						if (on_seg_weak(bomb, inx, p)) {//O(250 * 250 * 500)
							inx.i = on_seg_check(inx);
							if (inx.i == k) {
								if (!blocked(v, inx, -1, k) && !blocked(v, inx, k, inx.i)) {
									G[v.i].push_back(Info(goal, (v - inx).mag()));
								}
							}
							else {
								if (!blocked(v, inx, k, inx.i)) {
									G[v.i].push_back(Info(goal, (v - inx).mag()));
								}
							}
						}
					}
				}

				for (int k = 0; k < N; k++) {
					int szk = H[k].size();
					for (int l = 0; l < szk; l++) {//O(250 * 250)
						Pos& a = H[k][l], b = H[k][(l + 1) % szk];
						seg = L(a, b);
						if (zero(safe / seg)) continue;

						inx = intersection(safe, seg);
						if (!on_seg_weak(a, b, inx)) continue;
						if (!on_seg_weak(bomb, inx, p)) continue;
						if (meaningless(bomb, inx)) continue;

						inx.i = on_seg_check(inx);
						if (inx.i == X) {//O(250 * 250 * 500)
							if (!blocked(s, inx, -1, inx.i) && !blocked(s, inx, X, inx.i))
								G[1].push_back(Info(goal, (s - inx).mag()));
						}
						else {
							if (!blocked(s, inx, X, inx.i))
								G[1].push_back(Info(goal, (s - inx).mag()));
						}
						for (int m = 0; m < N; m++) {
							int szm = H[m].size();
							for (int n = 0; n < szm; n++) {//O(250 * 250 * 250)
								Pos& v = H[m][n];
								if (v.good) continue;
								if (inx.i == m) {//O(250 * 250 * 250 * 500)
									if (!blocked(v, inx, -1, m) && !blocked(v, inx, m, inx.i)) {
										G[v.i].push_back(Info(goal, (v - inx).mag()));
									}
								}
								else {
									if (!blocked(v, inx, m, inx.i)) {
										G[v.i].push_back(Info(goal, (v - inx).mag()));
									}
								}
							}
						}
					}
				}
			}
		}
	}
	for (int i = 0; i < N; i++) {
		int szi = H[i].size();
		for (int j = 0; j < szi; j++) {//O(500)
			Pos& u = H[i][j];
			if (i == X) {
				if (!blocked(s, u, X, i) && !blocked(s, u, -1, -2)) {
					G[1].push_back(Info(u.i, (u - s).mag()));
					//std::cout << "fucked\n";
					//std::cout << u << "\n";
				}
			}
			else {
				if (!blocked(s, u, X, i)) {
					G[1].push_back(Info(u.i, (u - s).mag()));
				}
			}
			for (int k = i; k < N; k++) {
				int szk = H[k].size();
				for (int l = 0; l < szk; l++) {//O(500 * 500)
					Pos& v = H[k][l];
					if (u.good && v.good) continue;
					if (i == k) {
						if (!blocked(u, v, i, k) && !blocked(u, v, -1, -2)) {
							G[u.i].push_back(Info(v.i, (u - v).mag()));
							G[v.i].push_back(Info(u.i, (u - v).mag()));
						}
					}
					else {
						if (!blocked(u, v, i, k)) {
							G[u.i].push_back(Info(v.i, (u - v).mag()));
							G[v.i].push_back(Info(u.i, (u - v).mag()));
						}
					}
				}
			}
		}
	}
	//std::cout << X << "\n";
	//for (int i = 0; i < T; i++) {
	//	for (Info& i : G[i]) std::cout << i.i << " " << i.c << "\n";
	//	std::cout << "DEBUG\n";
	//}
	ld cost = dijkstra(s.i, goal);
	return cost;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (1) {
		std::cin >> N;
		if (!N) break;
		std::cout << query() << "\n";
	}
	return;
}
int main() { solve(); return 0; }//JAG Practice Contest 2010 E boj13801


/*

1
1 1
4 -1 0 -2 -1 -1 -2 0 -1
1
0 3
4 1 1 1 2 -1 2 -1 1
1
-6 -6
6 1 -2 2 -2 2 3 -2 3 -2 1 1 1
1
6 4
6 5 -498 6 2 5 2 5 1 3 1 -999 -498
1
-10 0
4 0 -5 1 -5 1 5 0 5
1
-10 0
4 0 0 2 -2 1 0 2 2
1
-10 0
4 1 0 3 -2 2 0 3 2
1
-5 -1
4 -10 -1 -9 0 -10 1 -11 0
0

1.0
0.0
3.23606798
4.66227766
5.0000000000
2.8284271247
3.6055512755
10.0498756211

*/
accuracy: 1
time_ms: 1630
memory_kb: 6992
final_rank: 10

code_snippet: #include "bits/stdc++.h"

#define all(x)   x.begin(), x.end()
#define NL       std::cout << '\n'

using lnt = long long;

const int inf = 0x3f3f3f3f;
const lnt linf = 1ll << 61;

using db = long double; const db eps = 1e-7;
int sgn(db x) { return (x < -eps ? -1 : x > eps); }

struct Pt { db x, y; };
std::istream& operator>>(std::istream& is, Pt &p) {
  int x, y; std::cin >> x >> y;
  p.x = x; p.y = y; return is;
}
std::ostream& operator<<(std::ostream& os, Pt p) {
  return os << "(" << p.x << "," << p.y << ")";
}

Pt operator-(Pt a, Pt b) { return { a.x - b.x, a.y - b.y }; }
Pt operator+(Pt a, Pt b) { return { a.x + b.x, a.y + b.y }; }
Pt operator*(Pt a, db x) { return { a.x * x, a.y * x }; }
Pt operator/(Pt a, db x) { return { a.x / x, a.y / x }; }
db dot(Pt a, Pt b) { return a.x * b.x + a.y * b.y; }
db det(Pt a, Pt b) { return a.x * b.y - a.y * b.x; }
bool operator==(Pt a, Pt b) { return !sgn(dot(a-b, a-b)); }
bool operator!=(Pt a, Pt b) { return sgn(dot(a-b, a-b)); }
bool operator<(Pt a, Pt b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }
db dis2(Pt a, Pt b) { return dot(a-b, a-b); }
db dis(Pt a, Pt b) { return std::sqrt(dis2(a, b)); }
int side(Pt a, Pt b, Pt x) { return sgn(det(b-a, x-a)); }
Pt rot90(Pt a) { return {-a.y, a.x}; }
Pt rot(Pt a, db t) {
  return { a.x * std::cos(t) - a.y * std::sin(t)
         , a.x * std::sin(t) + a.y * std::cos(t) };
}
Pt unit(Pt a) {
  db d = dis(a, {0, 0});
  return sgn(d) ? a/d : Pt{0, 0};
}


struct Line { Pt s, t; };

Pt intersect(Line a, Line b) {
  db v = det(a.t - a.s, b.s - a.s);
  db u = det(a.t - a.s, b.t - a.s);
  return (b.s * u - b.t * v) / (u - v);
}
bool para(Line a, Line b) {
  return !sgn(det(a.t - a.s, b.t - b.s));
}

bool ptOnSeg(Pt x, Line v) {
  if (v.s == v.t) { return sgn(dis2(v.s, x)) == 0; }
  return sgn(det(v.s - x, v.t - x)) == 0
      && sgn(dot(v.s - x, v.t - x)) <= 0;
}

bool ptOnSeg_strict(Pt x, Line v) {
  if (v.s == v.t) { return sgn(dis2(v.s, x)) == 0; }
  return sgn(det(v.s - x, v.t - x)) == 0
      && sgn(dot(v.s - x, v.t - x)) < 0;
}

bool segInter(Line a, Line b) {
  if (sgn(det(b.s-a.s, a.t-a.s)) * sgn(det(b.t-a.s, a.t-a.s)) == -1
   && sgn(det(a.s-b.s, b.t-b.s)) * sgn(det(a.t-b.s, b.t-b.s)) == -1) {
    return true;
  }
  return false;
}

bool ptInPoly(Pt p, std::vector<Pt> &v) {
  int cnt = 0;
  for (int i = v.size() - 1, j = 0; j < v.size() - 2; i = j++) {
    if (ptOnSeg(p, {v[i], v[j]})) { return true; }
    int x = sgn(det(p - v[i], v[j] - v[i]));
    int y = sgn(v[i].y - p.y);
    int z = sgn(v[j].y - p.y);
    if (x > 0 && y <= 0 && z > 0) { ++cnt; }
    if (x < 0 && z <= 0 && y > 0) { --cnt; }
  }
  return cnt != 0;
}


Pt projection(Pt p, Line l) {
  Pt v = l.t - l.s;
  return l.s + v * (dot(p - l.s, v) / dot(v, v));
}

bool segInPoly(Line s, std::vector<Pt> &v) {
  const int n = v.size();
  for (int i = 0; i < n - 2; ++i) {
    const Pt a = v[i], b = v[(i+1)], c = v[(i+2)];
    if (segInter(s, {a, b})) { return false; }
    if (ptOnSeg_strict(s.s, {a, b}) && side(a, b, s.t) < 0) { return false; }
    if (ptOnSeg_strict(s.t, {a, b}) && side(a, b, s.s) < 0) { return false; }
    if (ptOnSeg(b, s)) {
      bool ok = true, acute = side(a, b, c) > 0;
      for (auto x : {s.s, s.t}) {
        if (acute) {
          ok &= side(a, b, x) >= 0 && side(b, c, x) >= 0;
        } else {
          ok &= side(a, b, x) >= 0 || side(b, c, x) >= 0;
        }
      }
      if (!ok) { return false; }
    }
  }
  return true;
}

int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0);
  int n;
  const Pt alice = {0, 0};
  while (std::cin >> n && n) {
    Pt bomb; std::cin >> bomb;
    std::vector<std::vector<Pt>> poly(n);
    std::vector<std::vector<Pt>> rpoly(n);
    for (int i = 0; i < n; ++i) {
      int k; std::cin >> k;
      poly[i].resize(k);
      for (int j = 0; j < k; ++j) {
        std::cin >> poly[i][j];
      }
      rpoly[i] = poly[i];
      std::reverse(all(rpoly[i]));
      poly[i].emplace_back(poly[i][0]);   poly[i].emplace_back(poly[i][1]);
      rpoly[i].emplace_back(rpoly[i][0]); rpoly[i].emplace_back(rpoly[i][1]);
    }


    auto visible = [&](Pt u, Pt v) {
      for (int i = 0; i < n; ++i) {
        if (!segInPoly({u, v}, rpoly[i])) { return false; }
      }
      return true;
    };

    auto alive = [&](Pt u) {
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < poly[j].size() - 2; ++k) {
          Pt a = poly[j][k], b = poly[j][k+1], c = poly[j][k+2];
          if (segInter({a, b}, {bomb, u})) { return true; }
          if (!sgn(det(u - bomb, a - bomb))
              && sgn(dot(bomb - u, a - u)) > 0
              && sgn(dot(u - bomb, a - bomb)) >= 0) { return true; }
          if ((b == u) && (side(bomb, u, a) == side(bomb, u, c))) { return true; }
        }
      }
      return false;
    };

    if (!visible(bomb, alice)) {
      std::cout << "0"; NL;
      continue;
    }

    std::vector<Pt> vt({alice});
    for (int i = 0; i < n; ++i) {
      for (auto x : poly[i]) {
        vt.emplace_back(x);
      }
    }

    std::vector<Line> ls;

    std::sort(vt.begin() + 1, vt.end());
    vt.erase(std::unique(all(vt)), vt.end());

    for (auto x : vt) {
      if (alive(x)) {
        ls.push_back({bomb, x});
      }
    }


    std::vector<Pt> v3;
    for (const auto &l : ls) {
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < poly[i].size() - 2; ++j) {
          if (side(l.s, l.t, poly[i][j]) * side(l.s, l.t, poly[i][j+1]) != -1) { continue; }
          Pt inter = intersect(l, {poly[i][j], poly[i][j+1]});
          if (alive(inter)) { v3.emplace_back(inter); }
        }
      }
    }

    std::sort(all(v3));
    v3.erase(std::unique(all(v3)), v3.end());

    db ret = inf;
    std::vector<db> d(vt.size(), inf);
    std::priority_queue<std::pair<db, int>, std::vector<std::pair<db, int>>, std::greater<>> q;
    d[0] = 0;
    q.emplace(0, 0);
    while (!q.empty()) {
      auto [ddis, u] = q.top(); q.pop();
      if (ret < ddis) { break; }
      if (d[u] < ddis) { continue; }
      if (alive(vt[u])) { ret = ddis; break; }
      for (auto l : ls) {
        Pt proj = projection(vt[u], l);
        if (visible(proj, vt[u]) && alive(proj)) { ret = std::min(ret, ddis + dis(proj, vt[u])); }
      }
      for (auto x : v3) {
        if (visible(x, vt[u])) {  ret = std::min(ret, ddis + dis(x, vt[u])); }
      }
      for (int v = 0; v < vt.size(); ++v) {
        db w = dis(vt[v], vt[u]);
        if (w + ddis >= d[v] || !visible(vt[v], vt[u])) { continue; }
        d[v] = w + ddis;
        q.emplace(d[v], v);
      }
    }
    std::cout << std::fixed << std::setprecision(8);
    std::cout << ret; NL;
  }

  return 0;
}
accuracy: 1
time_ms: 4110
memory_kb: 3648
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define Vector Point
const double eps = 1e-10, pi = acos(-1.0);
double Sqr(const double &x) {
	return x * x;
}
int Dcmp(const double &x) {
	return x < -eps ? -1 : x > eps ? 1 : 0;
}
struct Point {
	double x, y;
	Point(double x = 0, double y = 0) : x(x), y(y) {}
	int operator == (const Point &rhs) const {
		return Dcmp(x - rhs.x) == 0 && Dcmp(y - rhs.y) == 0;
	}
	Point operator + (const Point &rhs) const {
		return Point(x + rhs.x, y + rhs.y);
	}
	Point operator - (const Point &rhs) const {
		return Point(x - rhs.x, y - rhs.y);
	}
	Point operator * (const double &k) const {
		return Point(x * k, y * k);
	}
	Point operator / (const double &k) const {
		return Point(x / k, y / k);
	}
	double operator ^ (const Point &rhs) const {
		return x * rhs.y - y * rhs.x;
	}
	double operator * (const Point &rhs) const {
		return x * rhs.x + y * rhs.y;
	}
	double len2() {
		return x * x + y * y;
	}
	double len() {
		return sqrt(len2());
	}
	Point Rotate90() {
		return Point(-y, x);
	}
	Point Rotate(const double &rad) { // counterclockwise
		return Point(x * cos(rad) - y * sin(rad), x * sin(rad) + y * cos(rad));
	}
	Point Unit() {
		double l = len();
		return (*this) / l;
	}
}bomb, alice;
struct Seg {
	Point s, t;
	Seg(Point s = Point(), Point t = Point()) : s(s), t(t) {}
};
Point poly[105][105], s[505];
int safe[105][105], id[105][105], n, tot[105], vis[505];
double dis[505], rd[505][505];
struct Node {
	double dis;
	int id;
	Node(double dis = 0, int id = 0) : dis(dis), id(id) {}
	inline bool operator < (const Node &rhs) const {
		return Dcmp(dis - rhs.dis) > 0;
	}
};
inline int Intersect(Seg s1, Seg s2) {
// cerr << s1.s.x << " " << s1.s.y << " " << s1.t.x << " " << s1.t.y << endl;
// cerr << s2.s.x << " " << s2.s.y << " " << s2.t.x << " " << s2.t.y << endl;
// cerr << ((s1.t - s1.s) ^ (s2.s - s1.s)) * ((s1.t - s1.s) ^ (s2.t - s1.s)) << endl;
// cerr << ((s2.t - s2.s) ^ (s1.s - s2.s)) * ((s2.t - s2.s) ^ (s1.t - s2.s)) << endl;
	return Dcmp(((s1.t - s1.s) ^ (s2.s - s1.s)) * ((s1.t - s1.s) ^ (s2.t - s1.s))) < 0 && Dcmp(((s2.t - s2.s) ^ (s1.s - s2.s)) * ((s2.t - s2.s) ^ (s1.t - s2.s))) < 0;
}
inline int Can(Point a, Point b) {
	Seg now = Seg(a, b);
	for(int i = 1; i <= n; ++ i)
		for(int j = 0; j < tot[i]; ++ j)
			if(Intersect(now, Seg(poly[i][j], poly[i][j + 1])))
				return 0;
	return 1;
}
inline Point Inter(Seg l1, Seg l2) {
// cerr << l1.s.x << " " << l1.s.y << " " << l1.t.x << " " << l1.t.y << endl;
// cerr << l2.s.x << " " << l2.s.y << " " << l2.t.x << " " << l2.t.y << endl;
	double a1 = (l2.t - l2.s) ^ (l1.s - l2.s), a2 = (l2.t - l2.s) ^ (l1.t - l2.s);
// cerr << a1 << " " << a2 << endl;
	return (l1.s * a2 - l1.t * a1) / (a2 - a1);
}
inline Point Vertical(Point p, Seg s) {
	Point v = s.t - s.s;
	v = v.Rotate90();
	return Inter(Seg(p, p + v), s);
}
inline int OnSeg(Point p, Seg s) {
	if(Dcmp((p - s.s) * (s.t - s.s)) < 0)
		return 0;
	if(Dcmp((p - s.t) * (s.s - s.t)) < 0)
		return 0;
	return 1;
}
priority_queue<Node>q;
int main() {
	while(scanf("%d", &n) && n) {
		scanf("%lf%lf", &bomb.x, &bomb.y);
		int cnt = 0;
		for(int i = 1; i <= n; ++ i) {
			scanf("%d", &tot[i]);
			for(int j = 0; j < tot[i]; ++ j)
				scanf("%lf%lf", &poly[i][j].x, &poly[i][j].y);
			poly[i][tot[i]] = poly[i][0];
			for(int j = 0; j < tot[i]; ++ j)
				if(Dcmp((poly[i][j] - bomb) ^ (poly[i][j + 1] - bomb)) > 0)
					safe[i][j] = 1;
				else
					safe[i][j] = 0;
			for(int j = 1; j <= tot[i]; ++ j)
				s[++ cnt] = poly[i][j], vis[cnt] = safe[i][j - 1] | safe[i][j];
		}
// cerr << "????" << cnt << endl;
		if(!Can(s[0], bomb)) {
			printf("%.15f\n", 0.0);
			continue;
		}
		for(int i = 0; i <= cnt; ++ i) {
// cerr << s[i].x << " " << s[i].y << endl;
			rd[i][i] = 0;
			for(int j = i + 1; j <= cnt; ++ j)
				if(Can(s[i], s[j]))
					rd[i][j] = rd[j][i] = (s[i] - s[j]).len();
				else
					rd[i][j] = rd[j][i] = 1e18;
		}
		for(int i = 1; i <= cnt; ++ i)
			dis[i] = 1e18;
		q.push(Node(0, 0));
		while(!q.empty()) {
			Node now = q.top();
			q.pop();
			int id = now.id;
			if(Dcmp(dis[id] - now.dis))
				continue;
			for(int i = 1; i <= cnt; ++ i) {
				if(id == i)
					continue;
				if(dis[i] > dis[id] + rd[id][i])
					dis[i] = dis[id] + rd[id][i], q.push(Node(dis[i], i));
			}
		}
		double ans = 1e18;
		for(int i = 0; i <= cnt; ++ i) {
// cerr << dis[i] << endl;
			if(dis[i] > 1e17)
				continue;
			if(vis[i])
				ans = min(ans, dis[i]);
			for(int j = 1; j <= cnt; ++ j)
				if(vis[j] && Dcmp((s[i] - s[j]) * (bomb - s[j])) <= 0) {
		// cerr << i << " " << j << endl;
					Point v = Vertical(s[i], Seg(s[j], bomb));
		// cerr << (s[i] - v).len() << endl;
					ans = min(ans, dis[i] + (s[i] - v).len());
				}
		}
		printf("%.10f\n", ans);
	}
}
accuracy: 1
time_ms: 270
memory_kb: 5704
final_rank: 7

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



#define SIZE 10005
#define EPS2 0.1

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

   	/*
	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};

struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

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

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

	int node_id;
	double sum_dist;
};

int N;
int num_all;
int num_P[105],P[105][105],poly_index[SIZE];
int on_segment[SIZE];
double NUM = 100000;
double min_dist[SIZE];
Point A,B;
Point point[SIZE];
Polygon POLY[105];
vector<Edge> G[SIZE];


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

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

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

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

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

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

int ccw(Point p0,Point p1,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(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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 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(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(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(fabs(x1-x2) > EPS){
		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]);
}

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

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

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[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}

bool cross_check(Point from,Point to){

	Line tmp_line = Line(from,to);

	for(int i = 0; i < N; i++){
		for(int k = 0; k < num_P[i]; k++){
			Line work_line = Line(point[P[i][k]],point[P[i][(k+1)%num_P[i]]]);
			if(is_Cross(tmp_line,work_line)){

				Point cross_p = calc_Cross_Point(tmp_line,work_line);
				if(cross_p == from || cross_p == to){

					//両端点は除く
				}else{

					return true;
				}
			}
		}
	}
	return false;
}


void func(){

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

		POLY[i].clear();
	}

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

		on_segment[i] = -1;
		G[i].clear();
	}

	scanf("%lf %lf",&B.x,&B.y);

	num_all = 0;

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

		scanf("%d",&num_P[i]);
		for(int k = 0; k < num_P[i]; k++){

			scanf("%lf %lf",&point[num_all].x,&point[num_all].y);
			P[i][k] = num_all;
			POLY[i].push_back(point[num_all]);
			poly_index[num_all++] = i;
		}
	}

	if(cross_check(A,B)){

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

	vector<int> ok_P,not_cross_P;
	//避難可能な頂点を列挙
	for(int i = 0; i < num_all; i++){

		if(cross_check(B,point[i])){ //爆弾と自分を結ぶ線分がどこかのポリゴンと交差するならOK

			ok_P.push_back(i);

		}else{ //爆弾と自分を結ぶ線分を少し伸ばした点が、自分の属するポリゴンの内部に入るか調べる

			not_cross_P.push_back(i);

			Line tmp_line = Line(B,point[i]);
			double tmp_slope = calc_slope(tmp_line);

			bool FLG;
			Point tmp_p;

			if(fabs(tmp_slope-DBL_MAX) < EPS){

				if(B.y > point[i].y){

					tmp_p = Point(point[i].x,point[i].y-EPS2);

				}else{

					tmp_p = Point(point[i].x,point[i].y+EPS2);
				}

			}else{

				if(B.x < point[i].x){

					tmp_p = Point(point[i].x+EPS2,point[i].y+EPS2*tmp_slope);

				}else{

					tmp_p = Point(point[i].x-EPS2,point[i].y-EPS2*tmp_slope);
				}
			}

			if(contains(POLY[poly_index[i]],tmp_p) == 0){

				ok_P.push_back(i);
			}
		}
	}

	vector<int> seg_P,proj_P;

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

		Line tmp_line = Line(B,point[not_cross_P[i]]);
		double tmp_slope = calc_slope(tmp_line);

		//線分を延長する
		if(fabs(tmp_slope-DBL_MAX) < EPS){

			if(B.y > point[not_cross_P[i]].y){

				tmp_line.p[1] = Point(point[not_cross_P[i]].x,-NUM);

			}else{

				tmp_line.p[1] = Point(point[not_cross_P[i]].x,NUM);
			}

		}else{

			if(B.x < point[i].x){

				tmp_line.p[1] = Point(point[not_cross_P[i]].x+NUM,point[not_cross_P[i]].y+NUM*tmp_slope);

			}else{

				tmp_line.p[1] = Point(point[not_cross_P[i]].x-NUM,point[not_cross_P[i]].y-NUM*tmp_slope);
			}
		}

		tmp_line.p[0] = point[not_cross_P[i]];

		bool tmp_FLG = false;

		//線分とポリゴンの交点
		for(int k = 0; k < N; k++){
			if(tmp_FLG)break;
			if(k == poly_index[not_cross_P[i]])continue;

			for(int a = 0; a < num_P[k]; a++){
				Line work_line = Line(point[P[k][a]],point[P[k][(a+1)%num_P[k]]]);

				if(!is_Cross(tmp_line,work_line))continue;

				Point cross_p = calc_Cross_Point(tmp_line,work_line);

				if(!cross_check(point[not_cross_P[i]],cross_p)){ //tmp_lineにつき1つだけであるはず

					point[num_all] = cross_p;
					poly_index[num_all] = k;
					on_segment[num_all] = a;
					ok_P.push_back(num_all);
					seg_P.push_back(num_all);
					num_all++;
					tmp_FLG = true;
					break;
				}
			}
		}

		//Aからの垂線
		Point ref_p = calc_Reflection_Point(tmp_line,A);

		Line a_line = Line(A,ref_p);
		if(!is_Cross(a_line,tmp_line))continue;

		Point proj_p = calc_Cross_Point(tmp_line,a_line);
		if(calc_dist(B,proj_p)+EPS < calc_dist(B,point[not_cross_P[i]]))continue;

		if(!cross_check(A,proj_p)){

			point[num_all] = proj_p;
			poly_index[num_all] = -1;
			ok_P.push_back(num_all);
			proj_P.push_back(num_all);
			num_all++;
		}
	}

	/*辺張り*/

	//Aから
	for(int i = 0; i < num_all; i++){

		if(!cross_check(A,point[i])){

			G[num_all].push_back(Edge(i,calc_dist(A,point[i])));
		}
	}

	//ポリゴン同士
	for(int i = 0; i < N; i++){
		for(int k = 0; k < num_P[i]; k++){
			int from = P[i][k];
			int to = P[i][(k+1)%num_P[i]];

			double tmp_dist = calc_dist(point[from],point[to]);
			G[from].push_back(Edge(to,tmp_dist));
			G[to].push_back(Edge(from,tmp_dist));
		}
	}
	//辺上の点
	for(int i = 0; i < seg_P.size(); i++){

		//両隣の点
		int tmp = seg_P[i];
		int a = P[poly_index[tmp]][on_segment[tmp]];
		int b = P[poly_index[tmp]][(on_segment[tmp]+1)%num_P[poly_index[tmp]]];

		G[a].push_back(Edge(tmp,calc_dist(point[a],point[tmp])));
		G[b].push_back(Edge(tmp,calc_dist(point[b],point[tmp])));

		//他のポリゴンからの点
		for(int k = 0; k < N; k++){
			if(k == poly_index[tmp])continue;

			for(int a = 0; a < num_P[k]; a++){

				if(!cross_check(point[P[k][a]],point[tmp])){

					G[P[k][a]].push_back(Edge(tmp,calc_dist(point[P[k][a]],point[tmp])));
				}
			}
		}
	}

	//外にある点
	for(int i = 0; i < proj_P.size(); i++){

		int tmp = proj_P[i];

		//ポリゴンからの点
		for(int k = 0; k < N; k++){

			for(int a = 0; a < num_P[k]; a++){

				if(!cross_check(point[P[k][a]],point[tmp])){

					G[P[k][a]].push_back(Edge(tmp,calc_dist(point[P[k][a]],point[tmp])));
				}
			}
		}
	}

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

		min_dist[i] = BIG_NUM;
	}

	priority_queue<State> Q;
	min_dist[num_all] = 0;

	Q.push(State(num_all,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{

			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].dist;

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

			Q.pop();
		}
	}

	double ans = BIG_NUM;

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

		ans = min(ans,min_dist[ok_P[i]]);
	}

	printf("%.10lf\n",ans);
}

int main(){

	A = Point(0,0);

	while(true){

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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 450
memory_kb: 4152
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n)-1;i>=(a);i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
 
typedef double db;
 
const db EPS = 1e-9;
 
inline int sign(db a) {
    return a < -EPS ? -1 : a > EPS;
}
 
inline int cmp(db a, db b){
    return sign(a-b);
}
 
struct P {
    db x, y;
    P() {}
    P(db _x, db _y) : x(_x), y(_y) {}
    P operator+(P p) { return {x + p.x, y + p.y}; }
    P operator-(P p) { return {x - p.x, y - p.y}; }
    P operator*(db d) { return {x * d, y * d}; }
    P operator/(db d) { return {x / d, y / d}; }

    bool operator<(P p) const { 
        int c = cmp(x, p.x);
        if (c) return c == -1;
        return cmp(y, p.y) == -1;
    }

    bool operator==(P o) const{
        return cmp(x,o.x) == 0 && cmp(y,o.y) == 0;
    }

    db dot(P p) { return x * p.x + y * p.y; }
    db det(P p) { return x * p.y - y * p.x; }
    
    db distTo(P p) { return (*this-p).abs(); }
    db alpha() { return atan2(y, x); }
    void read() { cin>>x>>y; }
    void write() {cout<<"("<<x<<","<<y<<")"<<endl;}
    db abs() { return sqrt(abs2());}
    db abs2() { return x * x + y * y; }
    P rot90() { return P(-y,x);}
    P unit() { return *this/abs(); }
    int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
    P rot(db an){ return {x*cos(an)-y*sin(an),x*sin(an) + y*cos(an)}; }
};
 
struct L{ //ps[0] -> ps[1]
    P ps[2];
    P& operator[](int i) { return ps[i]; }
    P dir() { return ps[1] - ps[0]; }
    bool include(P p) { return sign((ps[1] - ps[0]).det(p - ps[0])) > 0; }
    L push(){ // push eps outward
        const double eps = 1e-6;
        P delta = (ps[1] - ps[0]).rot90().unit() * eps;
        return {ps[0] - delta, ps[1] - delta};
    }
};
 
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define crossOp(p1,p2,p3) sign(cross(p1,p2,p3))
 
bool chkLL(P p1, P p2, P q1, P q2) {
    db a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
    return sign(a1+a2) != 0;
}

P isLL(P p1, P p2, P q1, P q2) {
    db a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
    return (p1 * a2 + p2 * a1) / (a1 + a2);
}
 
P isLL(L l1,L l2){ return isLL(l1[0],l1[1],l2[0],l2[1]); }
 
bool intersect(db l1,db r1,db l2,db r2){
    if(l1>r1) swap(l1,r1); if(l2>r2) swap(l2,r2); 
    return !( cmp(r1,l2) == -1 || cmp(r2,l1) == -1 );
}
 
bool isSS(P p1, P p2, P q1, P q2){
    return intersect(p1.x,p2.x,q1.x,q2.x) && intersect(p1.y,p2.y,q1.y,q2.y) && 
    crossOp(p1,p2,q1) * crossOp(p1,p2,q2) <= 0 && crossOp(q1,q2,p1)
            * crossOp(q1,q2,p2) <= 0;
}
 
bool isSS_strict(P p1, P p2, P q1, P q2){
    return crossOp(p1,p2,q1) * crossOp(p1,p2,q2) < 0 && crossOp(q1,q2,p1)
            * crossOp(q1,q2,p2) < 0;
}
 
bool isMiddle(db a, db m, db b) {
    return sign(a - m) == 0 || sign(b - m) == 0 || (a < m != b < m);
}
 
bool isMiddle(P a, P m, P b) {
    return isMiddle(a.x, m.x, b.x) && isMiddle(a.y, m.y, b.y);
}
 
bool onSeg(P p1, P p2, P q){
    return crossOp(p1,p2,q) == 0 && isMiddle(p1, q, p2);
}

bool onSeg_strict(P p1, P p2, P q){
    return crossOp(p1,p2,q) == 0 && sign((q-p1).dot(p1-p2)) * sign((q-p2).dot(p1-p2)) < 0;
}
 
P proj(P p1, P p2, P q) {
    P dir = p2 - p1;
    return p1 + dir * (dir.dot(q - p1) / dir.abs2());
}
 
P reflect(P p1, P p2, P q){
    return proj(p1,p2,q) * 2 - q;
}
 
db nearest(P p1,P p2,P q){
    P h = proj(p1,p2,q);
    if(isMiddle(p1,h,p2))
        return q.distTo(h);
    return min(p1.distTo(q),p2.distTo(q));
}
 
db disSS(P p1, P p2, P q1, P q2){
    if(isSS(p1,p2,q1,q2)) return 0;
    return min(min(nearest(p1,p2,q1),nearest(p1,p2,q2)), min(nearest(q1,q2,p1),nearest(q1,q2,p2)) );
}
 
db rad(P p1,P p2){
    return atan2l(p1.det(p2),p1.dot(p2));
}
 
db incircle(P p1, P p2, P p3){
    db A = p1.distTo(p2);
    db B = p2.distTo(p3);
    db C = p3.distTo(p1);
    return sqrtl(A*B*C/(A+B+C));
}
 
//polygon
 
db area(vector<P> ps){
    db ret = 0; rep(i,0,ps.size()) ret += ps[i].det(ps[(i+1)%ps.size()]); 
    return ret/2;
}
 
int contain(vector<P> ps, P p){ //2:inside,1:on_seg,0:outside
    int n = ps.size(), ret = 0; 
    rep(i,0,n){
        P u=ps[i],v=ps[(i+1)%n];
        if(onSeg(u,v,p)) return 1;
        if(cmp(u.y,v.y)<=0) swap(u,v);
        if(cmp(p.y,u.y) >0 || cmp(p.y,v.y) <= 0) continue;
        ret ^= crossOp(p,u,v) > 0;
    }
    return ret*2;
}
 
vector<P> convexHull(vector<P> ps) {
    int n = ps.size(); if(n <= 1) return ps;
    sort(ps.begin(), ps.end());
    vector<P> qs(n * 2); int k = 0;
    for (int i = 0; i < n; qs[k++] = ps[i++]) 
        while (k > 1 && crossOp(qs[k - 2], qs[k - 1], ps[i]) <= 0) --k;
    for (int i = n - 2, t = k; i >= 0; qs[k++] = ps[i--])
        while (k > t && crossOp(qs[k - 2], qs[k - 1], ps[i]) <= 0) --k;
    qs.resize(k - 1);
    return qs;
}
 
vector<P> convexHullNonStrict(vector<P> ps) {
    //caution: need to unique the Ps first
    int n = ps.size(); if(n <= 1) return ps;
    sort(ps.begin(), ps.end());
    vector<P> qs(n * 2); int k = 0;
    for (int i = 0; i < n; qs[k++] = ps[i++]) 
        while (k > 1 && crossOp(qs[k - 2], qs[k - 1], ps[i]) < 0) --k;
    for (int i = n - 2, t = k; i >= 0; qs[k++] = ps[i--])
        while (k > t && crossOp(qs[k - 2], qs[k - 1], ps[i]) < 0) --k;
    qs.resize(k - 1);
    return qs;
}
 
db convexDiameter(vector<P> ps){
    int n = ps.size(); if(n <= 1) return 0;
    int is = 0, js = 0; rep(k,1,n) is = ps[k]<ps[is]?k:is, js = ps[js] < ps[k]?k:js;
    int i = is, j = js;
    db ret = ps[i].distTo(ps[j]);
    do{
        if((ps[(i+1)%n]-ps[i]).det(ps[(j+1)%n]-ps[j]) >= 0)
            (++j)%=n;
        else
            (++i)%=n;
        ret = max(ret,ps[i].distTo(ps[j]));
    }while(i!=is || j!=js);
    return ret;
}
 
vector<P> convexCut(const vector<P>&ps, P q1, P q2) {
    vector<P> qs;
    int n = ps.size();
    rep(i,0,n){
        P p1 = ps[i], p2 = ps[(i+1)%n];
        int d1 = crossOp(q1,q2,p1), d2 = crossOp(q1,q2,p2);
        if(d1 >= 0) qs.pb(p1);
        if(d1 * d2 < 0) qs.pb(isLL(p1,p2,q1,q2));
    }
    return qs;
}
 
//min_dist
 
db min_dist(vector<P>&ps,int l,int r){
    if(r-l<=5){
        db ret = 1e100;
        rep(i,l,r) rep(j,l,i) ret = min(ret,ps[i].distTo(ps[j]));
        return ret;
    }
    int m = (l+r)>>1;
    db ret = min(min_dist(ps,l,m),min_dist(ps,m,r));
    vector<P> qs; rep(i,l,r) if(abs(ps[i].x-ps[m].x)<= ret) qs.pb(ps[i]);
    sort(qs.begin(), qs.end(),[](P a,P b) -> bool {return a.y<b.y; });
    rep(i,1,qs.size()) for(int j=i-1;j>=0&&qs[j].y>=qs[i].y-ret;--j) ret = min(ret,qs[i].distTo(qs[j]));
    return ret;
}
 
int type(P o1,db r1,P o2,db r2){
    db d = o1.distTo(o2);
    if(cmp(d,r1+r2) == 1) return 4;
    if(cmp(d,r1+r2) == 0) return 3;
    if(cmp(d,abs(r1-r2)) == 1) return 2;
    if(cmp(d,abs(r1-r2)) == 0) return 1;
    return 0;
}
 
vector<P> isCL(P o,db r,P p1,P p2){
    db x = (p1-o).dot(p2-p1), y = (p2-p1).abs2(), d = x * x - y * ((p1-o).abs2() - r*r);
    if(sign(d) < 0) return {};
    d = max(d,0.0); P m = p1 - (p2-p1)*(x/y), dr = (p2-p1)*(sqrt(d)/y);
    return {m-dr,m+dr}; //along dir: p1->p2
}
 
vector<P> isCC(P o1, db r1, P o2, db r2) { //need to check whether two circles are the same
    db d = o1.distTo(o2); 
    if (cmp(d, r1 + r2) == 1) return {};
    d = min(d, r1 + r2);
    db y = (r1 * r1 + d * d - r2 * r2) / (2 * d), x = sqrt(r1 * r1 - y * y);
    P dr = (o2 - o1).unit();
    P q1 = o1 + dr * y, q2 = dr.rot90() * x;
    return {q1-q2,q1+q2};//along circle 1
}
 
vector<P> tanCP(P o, db r, P p) {
    db x = (p - o).abs2(), d = x - r * r;
    if (sign(d) <= 0) return {}; // on circle => no tangent
    P q1 = o + (p - o) * (r * r / x);
    P q2 = (p - o).rot90() * (r * sqrt(d) / x);
    return {q1-q2,q1+q2}; //counter clock-wise
}
 
 
vector<L> extanCC(P o1, db r1, P o2, db r2) {
    vector<L> ret;
    if (cmp(r1, r2) == 0) {
        P dr = (o2 - o1).unit().rot90() * r1;
        ret.pb({o1 + dr, o2 + dr}), ret.pb({o1 - dr, o2 - dr});
    } else {
        P p = (o2 * r1 - o1 * r2) / (r1 - r2);
        vector<P> ps = tanCP(o1, r1, p), qs = tanCP(o2, r2, p);
        rep(i,0,min(ps.size(),qs.size())) ret.pb({ps[i], qs[i]}); //c1 counter-clock wise
    }
    return ret;
}
 
vector<L> intanCC(P o1, db r1, P o2, db r2) {
    vector<L> ret;
    P p = (o1 * r2 + o2 * r1) / (r1 + r2);
    vector<P> ps = tanCP(o1,r1,p), qs = tanCP(o2,r2,p);
    rep(i,0,min(ps.size(),qs.size())) ret.pb({ps[i], qs[i]}); //c1 counter-clock wise
    return ret;
}
 
db areaCT(db r, P p1, P p2){
    vector<P> is = isCL(P(0,0),r,p1,p2);
    if(is.empty()) return r*r*rad(p1,p2)/2;
    bool b1 = cmp(p1.abs2(),r*r) == 1, b2 = cmp(p2.abs2(), r*r) == 1;
    if(b1 && b2){
        if(sign((p1-is[0]).dot(p2-is[0])) <= 0 &&
            sign((p1-is[0]).dot(p2-is[0])) <= 0)
        return r*r*(rad(p1,is[0]) + rad(is[1],p2))/2 + is[0].det(is[1])/2;
        else return r*r*rad(p1,p2)/2;
    }
    if(b1) return (r*r*rad(p1,is[0]) + is[0].det(p2))/2;
    if(b2) return (p1.det(is[1]) + r*r*rad(is[1],p2))/2;
    return p1.det(p2)/2;
}
 
bool parallel(L l0, L l1) { return sign( l0.dir().det( l1.dir() ) ) == 0; }
 
bool sameDir(L l0, L l1) { return parallel(l0, l1) && sign(l0.dir().dot(l1.dir()) ) == 1; }
 
bool cmp (P a,  P b) {
    if (a.quad() != b.quad()) {
        return a.quad() < b.quad();
    } else {
        return sign( a.det(b) ) > 0;
    }
}
 
bool operator < (L l0, L l1) {
    if (sameDir(l0, l1)) {
        return l1.include(l0[0]);
    } else {
        return cmp( l0.dir(), l1.dir() );
    }
}
 
bool check(L u, L v, L w) { 
    return w.include(isLL(u,v)); 
}
 
vector<P> halfPlaneIS(vector<L> &l) {
    sort(l.begin(), l.end());
    deque<L> q;
    for (int i = 0; i < (int)l.size(); ++i) {
        if (i && sameDir(l[i], l[i - 1])) continue;
        while (q.size() > 1 && !check(q[q.size() - 2], q[q.size() - 1], l[i])) q.pop_back();
        while (q.size() > 1 && !check(q[1], q[0], l[i])) q.pop_front();
        q.push_back(l[i]);
    }
    while (q.size() > 2 && !check(q[q.size() - 2], q[q.size() - 1], q[0])) q.pop_back();
    while (q.size() > 2 && !check(q[1], q[0], q[q.size() - 1])) q.pop_front();
    vector<P> ret;
    for (int i = 0; i < (int)q.size(); ++i) ret.push_back(isLL(q[i], q[(i + 1) % q.size()]));
    return ret;
}

P inCenter(P A, P B, P C) { // ??????
    double a = (B - C).abs(), b = (C - A).abs(), c = (A - B).abs();
    return (A * a + B * b + C * c) / (a + b + c);
}

P circumCenter(P a, P b, P c) { // ??????
    P bb = b - a, cc = c - a;
    double db = bb.abs2(), dc = cc.abs2(), d = 2 * bb.det(cc);
    return a - P(bb.y * dc - cc.y * db, cc.x * db - bb.x * dc) / d;
}

P othroCenter(P a, P b, P c) { // ??????
    P ba = b - a, ca = c - a, bc = b - c;
    double Y = ba.y * ca.y * bc.y,
    A = ca.x * ba.y - ba.x * ca.y,
    x0 = (Y + ca.x * ba.y * b.x - ba.x * ca.y * c.x) / A,
    y0 = -ba.x * (x0 - c.x) / ba.y + ca.y;
    return {x0, y0};
}

const int MAX_N = 500 + 10;

vector<P> ps[MAX_N];
vector<int> ids[MAX_N];

int n;
P bomb;
P O = {0,0};

vector<P> pList;

bool edge[MAX_N][MAX_N];
db len[MAX_N][MAX_N];

bool good[MAX_N];

int tot;

int total;

bool check(P L, P R, P p){
    //is p strictly belong to L -> R?
    if(L.det(R) > -EPS){ // <= 180 degree
        return L.det(p) > EPS && p.det(R) > EPS;
    }
    //L.det(R) < -EPS
    if(L.det(p) >= 0) return 1;
    if(p.det(R) > EPS) return 1;
    return 0;
}

bool strict_polys_segment(vector<P>&qs,P p1,P p2){
    int n = qs.size();

    P m = (p1+p2)/2;

    if(contain(qs,m) >= 2) return 1;

    rep(i,0,n){
        P q1 = qs[i], q2 = qs[(i+1)%n];
        if(isSS_strict(p1,p2,q1,q2)) return 1;
        if(onSeg_strict(p1,p2,q1)){
            P q0 = qs[(i+n-1)%n];
            if(check(q2-q1,q0-q1,p1-q1)) return 1;
            if(check(q2-q1,q0-q1,p2-q1)) return 1;
        }
    }

    return 0;
}

bool check_quick(P p1,P p2){
    rep(i,0,n)
        if(strict_polys_segment(ps[i],p1,p2)) return 0;
    return 1;
}

bool check_bf(P p1, P p2){

    bool touch = 0;
    rep(i,0,n){
        int m = ps[i].size();
        rep(j,0,m){
            P q1 = ps[i][j], q2 = ps[i][(j+1)%m];
            if(isSS_strict(p1,p2,q1,q2)) return 0;
            if(isSS(p1,p2,q1,q2)) touch = 1;
        }
    }

    if(!touch) return 1;

    //bf n^2
    if(p2 < p1) swap(p1,p2);


    rep(i,0,n){
        int m = ps[i].size();

        vector<P> is = {p1,p2};

        rep(j,0,m){            
            P q1 = ps[i][j], q2 = ps[i][(j+1)%m];
            if(chkLL(p1,p2,q1,q2)){
                P u = isLL(p1,p2,q1,q2);
                if(isMiddle(p1,u,p2))
                    is.pb(u);
            }
        }

        sort(is.begin(), is.end());

        rep(j,0,is.size() - 1){
            if(is[j].distTo(is[j+1]) < EPS) continue;
            P m = (is[j] + is[j+1]) / 2;
            ++total;
            if(contain(ps[i],m) == 2) return 0;
        }
    }

    return 1;
}

bool check(P p1,P p2){
    return check_quick(p1,p2);
}

vector<P> remove_colinear_point(vector<P> ps){
    deque<P> que;
    for(auto p : ps){
        while(que.size() >= 2 && crossOp(que[que.size()-2],que.back(),p) == 0)
            que.pop_back();
        que.push_back(p);
    }

    while(que.size() >= 3 && crossOp(que[que.size()-2],que.back(),que[0]) == 0)
        que.pop_back();

    while(que.size() >= 3 && crossOp(que.back(),que[0],que[1]) == 0)
        que.pop_front();

    ps = {};
    while(!que.empty()) ps.push_back(que.front()), que.pop_front();
    return ps;
}

int main(){
    while(cin>>n){
        if(!n) break;
        bomb.read();

        pList.clear();

        rep(i,0,n){
            ps[i].clear();
            ids[i].clear();

            int m;cin>>m;

            rep(j,0,m){
                P u; u.read(); 
                ps[i].pb(u); 
            }

            //ps[i] = remove_colinear_point(ps[i]);

            for(auto p : ps[i]){
                ids[i].pb(pList.size());
                pList.pb(p);
            }
        }

        pList.pb(O);pList.pb(bomb); tot = pList.size();

        if(!check_bf(O,bomb)){
            printf("%0.10f\n",0.0);
            continue;
        }

        rep(i,0,tot) rep(j,0,i){
            edge[i][j] = edge[j][i] = check(pList[i],pList[j]);
            len[i][j] = len[j][i] = pList[i].distTo(pList[j]);
        }

        memset(good,0,sizeof good);

        //get good edge

        rep(i,0,n){
            rep(j,0,ids[i].size()){
                int x = ids[i][j], y = ids[i][(j+1)%ids[i].size()];
                P u = (pList[x] + pList[y])/2;
                if(!check(u,bomb))
                    good[x] = good[y] = 1;
            }
        }

        db dist[MAX_N];
        bool used[MAX_N] = {};

        rep(i,0,tot) dist[i] = 1e100;

        dist[tot-2] = 0;

        db ans = 1e100;

        rep(_,0,tot){
            int u = -1; rep(i,0,tot) if(!used[i] && (u == -1 || dist[i] < dist[u]) ) u = i;
            used[u] = 1;
            rep(j,0,tot) if(edge[u][j] && dist[u] + len[u][j] < dist[j])
                dist[j] = dist[u] + len[u][j];
        }

        rep(i,0,tot) if(good[i]) ans = min(ans,dist[i]); db first = ans;
        
        rep(i,0,tot) if(dist[i] < ans){
            rep(j,0,tot-2){
                P u = proj(bomb,pList[j],pList[i]);
                db ret = dist[i] + pList[i].distTo(u);
                if(ret < ans){
                    if(u.dot(pList[j] - bomb) > pList[j].dot(pList[j] - bomb) && check(pList[i],u))
                        ans = ret;
                }
            }
        } 
        

        printf("%0.10f\n",ans);//cout<<"TOTAL:"<<total<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 3020
memory_kb: 5724
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n)-1;i>=(a);i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
 
typedef double db;
 
const db EPS = 1e-9;
 
inline int sign(db a) {
    return a < -EPS ? -1 : a > EPS;
}
 
inline int cmp(db a, db b){
    return sign(a-b);
}
 
struct P {
    db x, y;
    P() {}
    P(db _x, db _y) : x(_x), y(_y) {}
    P operator+(P p) { return {x + p.x, y + p.y}; }
    P operator-(P p) { return {x - p.x, y - p.y}; }
    P operator*(db d) { return {x * d, y * d}; }
    P operator/(db d) { return {x / d, y / d}; }

    bool operator<(P p) const { 
        int c = cmp(x, p.x);
        if (c) return c == -1;
        return cmp(y, p.y) == -1;
    }

    bool operator==(P o) const{
        return cmp(x,o.x) == 0 && cmp(y,o.y) == 0;
    }

    db dot(P p) { return x * p.x + y * p.y; }
    db det(P p) { return x * p.y - y * p.x; }
    
    db distTo(P p) { return (*this-p).abs(); }
    db alpha() { return atan2(y, x); }
    void read() { cin>>x>>y; }
    void write() {cout<<"("<<x<<","<<y<<")"<<endl;}
    db abs() { return sqrt(abs2());}
    db abs2() { return x * x + y * y; }
    P rot90() { return P(-y,x);}
    P unit() { return *this/abs(); }
    int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
    P rot(db an){ return {x*cos(an)-y*sin(an),x*sin(an) + y*cos(an)}; }
};
 
struct L{ //ps[0] -> ps[1]
    P ps[2];
    P& operator[](int i) { return ps[i]; }
    P dir() { return ps[1] - ps[0]; }
    bool include(P p) { return sign((ps[1] - ps[0]).det(p - ps[0])) > 0; }
    L push(){ // push eps outward
        const double eps = 1e-6;
        P delta = (ps[1] - ps[0]).rot90().unit() * eps;
        return {ps[0] - delta, ps[1] - delta};
    }
};
 
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define crossOp(p1,p2,p3) sign(cross(p1,p2,p3))
 
bool chkLL(P p1, P p2, P q1, P q2) {
    db a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
    return sign(a1+a2) != 0;
}

P isLL(P p1, P p2, P q1, P q2) {
    db a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
    return (p1 * a2 + p2 * a1) / (a1 + a2);
}
 
P isLL(L l1,L l2){ return isLL(l1[0],l1[1],l2[0],l2[1]); }
 
bool intersect(db l1,db r1,db l2,db r2){
    if(l1>r1) swap(l1,r1); if(l2>r2) swap(l2,r2); 
    return !( cmp(r1,l2) == -1 || cmp(r2,l1) == -1 );
}
 
bool isSS(P p1, P p2, P q1, P q2){
    return intersect(p1.x,p2.x,q1.x,q2.x) && intersect(p1.y,p2.y,q1.y,q2.y) && 
    crossOp(p1,p2,q1) * crossOp(p1,p2,q2) <= 0 && crossOp(q1,q2,p1)
            * crossOp(q1,q2,p2) <= 0;
}
 
bool isSS_strict(P p1, P p2, P q1, P q2){
    return crossOp(p1,p2,q1) * crossOp(p1,p2,q2) < 0 && crossOp(q1,q2,p1)
            * crossOp(q1,q2,p2) < 0;
}
 
bool isMiddle(db a, db m, db b) {
    return sign(a - m) == 0 || sign(b - m) == 0 || (a < m != b < m);
}
 
bool isMiddle(P a, P m, P b) {
    return isMiddle(a.x, m.x, b.x) && isMiddle(a.y, m.y, b.y);
}
 
bool onSeg(P p1, P p2, P q){
    return crossOp(p1,p2,q) == 0 && isMiddle(p1, q, p2);
}

bool onSeg_strict(P p1, P p2, P q){
    return crossOp(p1,p2,q) == 0 && sign((q-p1).dot(p1-p2)) * sign((q-p2).dot(p1-p2)) < 0;
}
 
P proj(P p1, P p2, P q) {
    P dir = p2 - p1;
    return p1 + dir * (dir.dot(q - p1) / dir.abs2());
}
 
P reflect(P p1, P p2, P q){
    return proj(p1,p2,q) * 2 - q;
}
 
db nearest(P p1,P p2,P q){
    P h = proj(p1,p2,q);
    if(isMiddle(p1,h,p2))
        return q.distTo(h);
    return min(p1.distTo(q),p2.distTo(q));
}
 
db disSS(P p1, P p2, P q1, P q2){
    if(isSS(p1,p2,q1,q2)) return 0;
    return min(min(nearest(p1,p2,q1),nearest(p1,p2,q2)), min(nearest(q1,q2,p1),nearest(q1,q2,p2)) );
}
 
db rad(P p1,P p2){
    return atan2l(p1.det(p2),p1.dot(p2));
}
 
db incircle(P p1, P p2, P p3){
    db A = p1.distTo(p2);
    db B = p2.distTo(p3);
    db C = p3.distTo(p1);
    return sqrtl(A*B*C/(A+B+C));
}
 
//polygon
 
db area(vector<P> ps){
    db ret = 0; rep(i,0,ps.size()) ret += ps[i].det(ps[(i+1)%ps.size()]); 
    return ret/2;
}
 
int contain(vector<P> ps, P p){ //2:inside,1:on_seg,0:outside
    int n = ps.size(), ret = 0; 
    rep(i,0,n){
        P u=ps[i],v=ps[(i+1)%n];
        if(onSeg(u,v,p)) return 1;
        if(cmp(u.y,v.y)<=0) swap(u,v);
        if(cmp(p.y,u.y) >0 || cmp(p.y,v.y) <= 0) continue;
        ret ^= crossOp(p,u,v) > 0;
    }
    return ret*2;
}
 
vector<P> convexHull(vector<P> ps) {
    int n = ps.size(); if(n <= 1) return ps;
    sort(ps.begin(), ps.end());
    vector<P> qs(n * 2); int k = 0;
    for (int i = 0; i < n; qs[k++] = ps[i++]) 
        while (k > 1 && crossOp(qs[k - 2], qs[k - 1], ps[i]) <= 0) --k;
    for (int i = n - 2, t = k; i >= 0; qs[k++] = ps[i--])
        while (k > t && crossOp(qs[k - 2], qs[k - 1], ps[i]) <= 0) --k;
    qs.resize(k - 1);
    return qs;
}
 
vector<P> convexHullNonStrict(vector<P> ps) {
    //caution: need to unique the Ps first
    int n = ps.size(); if(n <= 1) return ps;
    sort(ps.begin(), ps.end());
    vector<P> qs(n * 2); int k = 0;
    for (int i = 0; i < n; qs[k++] = ps[i++]) 
        while (k > 1 && crossOp(qs[k - 2], qs[k - 1], ps[i]) < 0) --k;
    for (int i = n - 2, t = k; i >= 0; qs[k++] = ps[i--])
        while (k > t && crossOp(qs[k - 2], qs[k - 1], ps[i]) < 0) --k;
    qs.resize(k - 1);
    return qs;
}
 
db convexDiameter(vector<P> ps){
    int n = ps.size(); if(n <= 1) return 0;
    int is = 0, js = 0; rep(k,1,n) is = ps[k]<ps[is]?k:is, js = ps[js] < ps[k]?k:js;
    int i = is, j = js;
    db ret = ps[i].distTo(ps[j]);
    do{
        if((ps[(i+1)%n]-ps[i]).det(ps[(j+1)%n]-ps[j]) >= 0)
            (++j)%=n;
        else
            (++i)%=n;
        ret = max(ret,ps[i].distTo(ps[j]));
    }while(i!=is || j!=js);
    return ret;
}
 
vector<P> convexCut(const vector<P>&ps, P q1, P q2) {
    vector<P> qs;
    int n = ps.size();
    rep(i,0,n){
        P p1 = ps[i], p2 = ps[(i+1)%n];
        int d1 = crossOp(q1,q2,p1), d2 = crossOp(q1,q2,p2);
        if(d1 >= 0) qs.pb(p1);
        if(d1 * d2 < 0) qs.pb(isLL(p1,p2,q1,q2));
    }
    return qs;
}
 
//min_dist
 
db min_dist(vector<P>&ps,int l,int r){
    if(r-l<=5){
        db ret = 1e100;
        rep(i,l,r) rep(j,l,i) ret = min(ret,ps[i].distTo(ps[j]));
        return ret;
    }
    int m = (l+r)>>1;
    db ret = min(min_dist(ps,l,m),min_dist(ps,m,r));
    vector<P> qs; rep(i,l,r) if(abs(ps[i].x-ps[m].x)<= ret) qs.pb(ps[i]);
    sort(qs.begin(), qs.end(),[](P a,P b) -> bool {return a.y<b.y; });
    rep(i,1,qs.size()) for(int j=i-1;j>=0&&qs[j].y>=qs[i].y-ret;--j) ret = min(ret,qs[i].distTo(qs[j]));
    return ret;
}
 
int type(P o1,db r1,P o2,db r2){
    db d = o1.distTo(o2);
    if(cmp(d,r1+r2) == 1) return 4;
    if(cmp(d,r1+r2) == 0) return 3;
    if(cmp(d,abs(r1-r2)) == 1) return 2;
    if(cmp(d,abs(r1-r2)) == 0) return 1;
    return 0;
}
 
vector<P> isCL(P o,db r,P p1,P p2){
    db x = (p1-o).dot(p2-p1), y = (p2-p1).abs2(), d = x * x - y * ((p1-o).abs2() - r*r);
    if(sign(d) < 0) return {};
    d = max(d,0.0); P m = p1 - (p2-p1)*(x/y), dr = (p2-p1)*(sqrt(d)/y);
    return {m-dr,m+dr}; //along dir: p1->p2
}
 
vector<P> isCC(P o1, db r1, P o2, db r2) { //need to check whether two circles are the same
    db d = o1.distTo(o2); 
    if (cmp(d, r1 + r2) == 1) return {};
    d = min(d, r1 + r2);
    db y = (r1 * r1 + d * d - r2 * r2) / (2 * d), x = sqrt(r1 * r1 - y * y);
    P dr = (o2 - o1).unit();
    P q1 = o1 + dr * y, q2 = dr.rot90() * x;
    return {q1-q2,q1+q2};//along circle 1
}
 
vector<P> tanCP(P o, db r, P p) {
    db x = (p - o).abs2(), d = x - r * r;
    if (sign(d) <= 0) return {}; // on circle => no tangent
    P q1 = o + (p - o) * (r * r / x);
    P q2 = (p - o).rot90() * (r * sqrt(d) / x);
    return {q1-q2,q1+q2}; //counter clock-wise
}
 
 
vector<L> extanCC(P o1, db r1, P o2, db r2) {
    vector<L> ret;
    if (cmp(r1, r2) == 0) {
        P dr = (o2 - o1).unit().rot90() * r1;
        ret.pb({o1 + dr, o2 + dr}), ret.pb({o1 - dr, o2 - dr});
    } else {
        P p = (o2 * r1 - o1 * r2) / (r1 - r2);
        vector<P> ps = tanCP(o1, r1, p), qs = tanCP(o2, r2, p);
        rep(i,0,min(ps.size(),qs.size())) ret.pb({ps[i], qs[i]}); //c1 counter-clock wise
    }
    return ret;
}
 
vector<L> intanCC(P o1, db r1, P o2, db r2) {
    vector<L> ret;
    P p = (o1 * r2 + o2 * r1) / (r1 + r2);
    vector<P> ps = tanCP(o1,r1,p), qs = tanCP(o2,r2,p);
    rep(i,0,min(ps.size(),qs.size())) ret.pb({ps[i], qs[i]}); //c1 counter-clock wise
    return ret;
}
 
db areaCT(db r, P p1, P p2){
    vector<P> is = isCL(P(0,0),r,p1,p2);
    if(is.empty()) return r*r*rad(p1,p2)/2;
    bool b1 = cmp(p1.abs2(),r*r) == 1, b2 = cmp(p2.abs2(), r*r) == 1;
    if(b1 && b2){
        if(sign((p1-is[0]).dot(p2-is[0])) <= 0 &&
            sign((p1-is[0]).dot(p2-is[0])) <= 0)
        return r*r*(rad(p1,is[0]) + rad(is[1],p2))/2 + is[0].det(is[1])/2;
        else return r*r*rad(p1,p2)/2;
    }
    if(b1) return (r*r*rad(p1,is[0]) + is[0].det(p2))/2;
    if(b2) return (p1.det(is[1]) + r*r*rad(is[1],p2))/2;
    return p1.det(p2)/2;
}
 
bool parallel(L l0, L l1) { return sign( l0.dir().det( l1.dir() ) ) == 0; }
 
bool sameDir(L l0, L l1) { return parallel(l0, l1) && sign(l0.dir().dot(l1.dir()) ) == 1; }
 
bool cmp (P a,  P b) {
    if (a.quad() != b.quad()) {
        return a.quad() < b.quad();
    } else {
        return sign( a.det(b) ) > 0;
    }
}
 
bool operator < (L l0, L l1) {
    if (sameDir(l0, l1)) {
        return l1.include(l0[0]);
    } else {
        return cmp( l0.dir(), l1.dir() );
    }
}
 
bool check(L u, L v, L w) { 
    return w.include(isLL(u,v)); 
}
 
vector<P> halfPlaneIS(vector<L> &l) {
    sort(l.begin(), l.end());
    deque<L> q;
    for (int i = 0; i < (int)l.size(); ++i) {
        if (i && sameDir(l[i], l[i - 1])) continue;
        while (q.size() > 1 && !check(q[q.size() - 2], q[q.size() - 1], l[i])) q.pop_back();
        while (q.size() > 1 && !check(q[1], q[0], l[i])) q.pop_front();
        q.push_back(l[i]);
    }
    while (q.size() > 2 && !check(q[q.size() - 2], q[q.size() - 1], q[0])) q.pop_back();
    while (q.size() > 2 && !check(q[1], q[0], q[q.size() - 1])) q.pop_front();
    vector<P> ret;
    for (int i = 0; i < (int)q.size(); ++i) ret.push_back(isLL(q[i], q[(i + 1) % q.size()]));
    return ret;
}

P inCenter(P A, P B, P C) { // ??????
    double a = (B - C).abs(), b = (C - A).abs(), c = (A - B).abs();
    return (A * a + B * b + C * c) / (a + b + c);
}

P circumCenter(P a, P b, P c) { // ??????
    P bb = b - a, cc = c - a;
    double db = bb.abs2(), dc = cc.abs2(), d = 2 * bb.det(cc);
    return a - P(bb.y * dc - cc.y * db, cc.x * db - bb.x * dc) / d;
}

P othroCenter(P a, P b, P c) { // ??????
    P ba = b - a, ca = c - a, bc = b - c;
    double Y = ba.y * ca.y * bc.y,
    A = ca.x * ba.y - ba.x * ca.y,
    x0 = (Y + ca.x * ba.y * b.x - ba.x * ca.y * c.x) / A,
    y0 = -ba.x * (x0 - c.x) / ba.y + ca.y;
    return {x0, y0};
}

const int MAX_N = 500 + 10;

vector<P> ps[MAX_N];
vector<int> ids[MAX_N];

int n;
P bomb;
P O = {0,0};

vector<P> pList;

bool edge[MAX_N][MAX_N];
db len[MAX_N][MAX_N];

bool good[MAX_N];

int tot;

int total;

bool check(P L, P R, P p){
    //is p strictly belong to L -> R?
    if(L.det(R) > -EPS){ // <= 180 degree
        return L.det(p) > EPS && p.det(R) > EPS;
    }
    //L.det(R) < -EPS
    if(L.det(p) >= 0) return 1;
    if(p.det(R) > EPS) return 1;
    return 0;
}

bool strict_polys_segment(vector<P>&qs,P p1,P p2){
    int n = qs.size();

    P m = (p1+p2)/2;

    if(contain(qs,m) >= 2) return 1;

    rep(i,0,n){
        P q1 = qs[i], q2 = qs[(i+1)%n];
        if(isSS_strict(p1,p2,q1,q2)) return 1;
        if(onSeg_strict(p1,p2,q1)){
            P q0 = qs[(i+n-1)%n];
            if(check(q2-q1,q0-q1,p1-q1)) return 1;
            if(check(q2-q1,q0-q1,p2-q1)) return 1;
        }
    }

    return 0;
}

bool check_quick(P p1,P p2){
    rep(i,0,n)
        if(strict_polys_segment(ps[i],p1,p2)) return 0;
    return 1;
}

bool check_bf(P p1, P p2){

    bool touch = 0;
    rep(i,0,n){
        int m = ps[i].size();
        rep(j,0,m){
            P q1 = ps[i][j], q2 = ps[i][(j+1)%m];
            if(isSS_strict(p1,p2,q1,q2)) return 0;
            if(isSS(p1,p2,q1,q2)) touch = 1;
        }
    }

    if(!touch) return 1;

    //bf n^2
    if(p2 < p1) swap(p1,p2);


    rep(i,0,n){
        int m = ps[i].size();

        vector<P> is = {p1,p2};

        rep(j,0,m){            
            P q1 = ps[i][j], q2 = ps[i][(j+1)%m];
            if(chkLL(p1,p2,q1,q2)){
                P u = isLL(p1,p2,q1,q2);
                if(isMiddle(p1,u,p2))
                    is.pb(u);
            }
        }

        sort(is.begin(), is.end());

        rep(j,0,is.size() - 1){
            if(is[j].distTo(is[j+1]) < EPS) continue;
            P m = (is[j] + is[j+1]) / 2;
            ++total;
            if(contain(ps[i],m) == 2) return 0;
        }
    }

    return 1;
}

bool check(P p1,P p2){
    return check_quick(p1,p2);
}

vector<P> remove_colinear_point(vector<P> ps){
    deque<P> que;
    for(auto p : ps){
        while(que.size() >= 2 && crossOp(que[que.size()-2],que.back(),p) == 0)
            que.pop_back();
        que.push_back(p);
    }

    while(que.size() >= 3 && crossOp(que[que.size()-2],que.back(),que[0]) == 0)
        que.pop_back();

    while(que.size() >= 3 && crossOp(que.back(),que[0],que[1]) == 0)
        que.pop_front();

    ps = {};
    while(!que.empty()) ps.push_back(que.front()), que.pop_front();
    return ps;
}

int main(){
    while(cin>>n){
        if(!n) break;
        bomb.read();

        pList.clear();

        rep(i,0,n){
            ps[i].clear();
            ids[i].clear();

            int m;cin>>m;

            rep(j,0,m){
                P u; u.read(); 
                ps[i].pb(u); 
            }

            ps[i] = remove_colinear_point(ps[i]);

            for(auto p : ps[i]){
                ids[i].pb(pList.size());
                pList.pb(p);
            }
        }

        pList.pb(O);pList.pb(bomb); tot = pList.size();

        if(!check_bf(O,bomb)){
            printf("%0.10f\n",0.0);
            continue;
        }

        rep(i,0,tot) rep(j,0,i){
            edge[i][j] = edge[j][i] = check(pList[i],pList[j]);
            len[i][j] = len[j][i] = pList[i].distTo(pList[j]);
        }

        memset(good,0,sizeof good);

        //get good edge

        rep(i,0,n){
            rep(j,0,ids[i].size()){
                int x = ids[i][j], y = ids[i][(j+1)%ids[i].size()];
                P u = (pList[x] + pList[y])/2;
                if(!check(u,bomb))
                    good[x] = good[y] = 1;
            }
        }

        db dist[MAX_N];
        bool used[MAX_N] = {};

        rep(i,0,tot) dist[i] = 1e100;

        dist[tot-2] = 0;

        db ans = 1e100;

        rep(_,0,tot){
            int u = -1; rep(i,0,tot) if(!used[i] && (u == -1 || dist[i] < dist[u]) ) u = i;
            used[u] = 1;
            rep(j,0,tot) if(edge[u][j] && dist[u] + len[u][j] < dist[j])
                dist[j] = dist[u] + len[u][j];
        }

        rep(i,0,tot) if(good[i]) ans = min(ans,dist[i]); db first = ans;
        
        rep(i,0,tot) if(dist[i] < ans){
            rep(j,0,tot-2){
                P u = proj(bomb,pList[j],pList[i]);
                db ret = dist[i] + pList[i].distTo(u);
                if(ret < ans){
                    if(u.dot(pList[j] - bomb) > pList[j].dot(pList[j] - bomb) && check(pList[i],u))
                        ans = ret;
                }
            }
        } 
        

        printf("%0.10f\n",ans);//cout<<"TOTAL:"<<total<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 3400
memory_kb: 5564
final_rank: 13

code_snippet: #include<bits/stdc++.h>
#define MAX 1024
#define inf 1<<29
#define linf 1e16
#define eps (1e-8)
#define mod 1000000007
#define pi acos(-1)
#define phi (1.0+sqrt(5))/2.0
#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<int,double> pid;
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 equals(x,p.x) ? y-p.y<-eps : x-p.x<-eps; }
  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){}
};
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);}
 
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);
}
 
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);
}
 
bool intersect(Segment a,Segment b){
  if(cross(a.p2-a.p1,b.p1-a.p1)*cross(a.p2-a.p1,b.p2-a.p1)<-eps &&
     cross(b.p2-b.p1,a.p1-b.p1)*cross(b.p2-b.p1,a.p2-b.p1)<-eps)
    return true;
  return false;
}
 
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);
}*/
 
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;
}
 
int n,m;
Point s,ori(0,0);
vector<Point> g;
vector<Polygon> buildings;
vector<Point> vp;
vector<pid> e[MAX];
 
void init(){
  buildings.clear();
  vp.clear();
  FOR(i,0,MAX)e[i].clear();
  g.clear();
}
 
void add_edge(int to,int from,double cost){
  e[to].pb(mp(from,cost));
  e[from].pb(mp(to,cost));
}
 
bool check(Point a){
  FOR(i,0,n)if(contains(buildings[i],a)==2)return false;
  return true;
}
 
bool check(Segment s){
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Point a=p[j],b=p[(j+1)%m],c=p[(j-1+m)%m];
      if(isParallel(Segment(a,b),s))continue;
      if(intersect(Segment(a,b),s))return false;
      if(ccw(s.p1,s.p2,a)==0 && !(s.p1==a) && !(s.p2==b)){
        if(ccw(s.p1,s.p2,b)*ccw(s.p1,s.p2,c)==-1)return false;
      }
    }
  }
  return true;
}
 
double getdis(Point a,Point b){
  Point c=project(Line(s,b),a);
  if(abs(c-s)<abs(b-s))return inf;
  if(check(a+(c-a)/2.0) && check(Segment(a,c)))return abs(c-a);
  return inf;
}
 
double dijkstra(){
  double d[MAX];
  priority_queue<pdi,vector<pdi>,greater<pdi> > pq;
  fill(d,d+MAX,inf);
  d[0]=0;
  pq.push(mp(0,0));
 
  while(pq.size()){
    pdi u=pq.top();
    pq.pop();
 
    if(d[u.s]<u.f)continue;
    if(u.s==vp.size())return u.f;
 
    FOR(i,0,e[u.s].size()){
      int next=e[u.s][i].f;
      double cost=e[u.s][i].s+d[u.s];
      if(cost<d[next]){
        d[next]=cost;
        pq.push(mp(cost,next));
      }
    }
  }
  return inf;
}
 
double solve(){
  if(!check(Segment(ori,s)))return 0;
  vp.pb(ori);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      vp.pb(p[j]);
      if(ccw(s,p[j],p[(j-1+m)%m])*
         ccw(s,p[j],p[(j+1)%m])==1)g.pb(p[j]);
    }
  }
   
  FOR(i,0,vp.size()){
    FOR(j,i+1,vp.size()){
      if(check(vp[i]+(vp[j]-vp[i])/2.0) && 
         check(Segment(vp[i],vp[j])))add_edge(i,j,abs(vp[i]-vp[j]));
    }
  }
  FOR(i,0,vp.size()){
    double cost=inf;
    FOR(j,0,g.size()){
      if(vp[i]==g[j])cost=0;
      else cost=min(cost,getdis(vp[i],g[j]));
    }
    add_edge(vp.size(),i,cost);
  }
  return dijkstra();
}
 
int main()
{
  while(cin>>n && n){
    init();
    cin>>s.x>>s.y;
    FOR(i,0,n){
      cin>>m;
      Polygon p;
      FOR(j,0,m){
        int x,y;
        cin>>x>>y;
        p.pb(Point(x,y));
      }
      buildings.pb(p);
    }
    pd(solve());
  }
  return 0;
}
accuracy: 1
time_ms: 5040
memory_kb: 5028
final_rank: 17

code_snippet: #include<bits/stdc++.h>
#define MAX 1024
#define inf 1<<29
#define linf 1e16
#define eps (1e-6)
#define mod 1000000007
#define pi acos(-1)
#define phi (1.0+sqrt(5))/2.0
#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<int,double> pid;
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 equals(x,p.x) ? y-p.y<-eps : x-p.x<-eps; }
  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){}
};
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);}

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

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

bool intersect(Segment a,Segment b){
  if(cross(a.p2-a.p1,b.p1-a.p1)*cross(a.p2-a.p1,b.p2-a.p1)<-eps &&
     cross(b.p2-b.p1,a.p1-b.p1)*cross(b.p2-b.p1,a.p2-b.p1)<-eps)
    return true;
  return false;
}

bool intersectLS(Line L,Segment s){
  return cross(L.p2-L.p1,s.p1-L.p1)*cross(L.p2-L.p1,s.p2-L.p1)<-eps;
}

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

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

int n,m;
Point s,ori(0,0);
vector<Point> g;
vector<Polygon> buildings;
vector<Point> vp;
vector<pid> e[MAX];

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

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

bool check(Point a){
  FOR(i,0,n)if(contains(buildings[i],a)==2)return false;
  return true;
}

bool check(Segment s){
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Point a=p[j],b=p[(j+1)%m],c=p[(j-1+m)%m];
      if(isParallel(Segment(a,b),s))continue;
      if(intersect(Segment(a,b),s))return false;
    }
  }
  return true;
}

double getdis(Point a,Point b){
  Line L(s,b);
  Point c=project(L,a);
  if(ccw(s,b,c)==-2 && check(a+(c-a)/2.0) &&
     check(Segment(a,c)))return abs(c-a);
  c=Point(inf,inf);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Segment seg(p[j],p[(j+1)%m]);
      if(isParallel(L,seg))continue;
      if(!intersectLS(L,seg))continue;
      Point cp=getCrossPointLL(L,seg);
      if(ccw(s,b,cp)==-2 && abs(s-cp)<abs(s-c))c=cp;
    }
  }
  if(ccw(s,b,c)==-2 && check(a+(c-a)/2.0) &&
     check(Segment(a,c)))return abs(c-a);
  return inf;
}

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

  while(pq.size()){
    pdi u=pq.top();
    pq.pop();

    if(d[u.s]<u.f)continue;
    if(u.s==vp.size())return u.f;

    FOR(i,0,e[u.s].size()){
      int next=e[u.s][i].f;
      double cost=e[u.s][i].s+d[u.s];
      if(cost<d[next]){
        d[next]=cost;
        pq.push(mp(cost,next));
      }
    }
  }
  return inf;
}

double solve(){
  if(!check(Segment(ori,s)))return 0;
  vp.pb(ori);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      if(!check(Segment(s,p[j])))continue;
      vp.pb(p[j]);
      if(ccw(s,p[j],p[(j-1+m)%m])*
         ccw(s,p[j],p[(j+1)%m])==1)g.pb(p[j]);
    }
  }
  
  FOR(i,0,vp.size()){
    FOR(j,i+1,vp.size()){
      if(check(vp[i]+(vp[j]-vp[i])/2.0) && 
         check(Segment(vp[i],vp[j])))add_edge(i,j,abs(vp[i]-vp[j]));
    }
  }
  FOR(i,0,vp.size()){
    double cost=inf;
    FOR(j,0,g.size()){
      if(vp[i]==g[j]){ cost=0;break; }
      else cost=min(cost,getdis(vp[i],g[j]));
    }
    add_edge(vp.size(),i,cost);
  }
  return dijkstra();
}

int main()
{
  while(cin>>n && n){
    init();
    cin>>s.x>>s.y;
    FOR(i,0,n){
      cin>>m;
      Polygon p;
      FOR(j,0,m){
        int x,y;
        cin>>x>>y;
        p.pb(Point(x,y));
      }
      buildings.pb(p);
    }
    pd(solve());
  }
  return 0;
}
accuracy: 1
time_ms: 2800
memory_kb: 6896
final_rank: 15

code_snippet: #include<bits/stdc++.h>
#define MAX 1024
#define inf 1<<29
#define linf 1e16
#define eps (1e-6)
#define mod 1000000007
#define pi acos(-1)
#define phi (1.0+sqrt(5))/2.0
#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<int,double> pid;
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 equals(x,p.x) ? y-p.y<-eps : x-p.x<-eps; }
  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){}
};
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);}

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

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

bool intersect(Segment a,Segment b){
  if(cross(a.p2-a.p1,b.p1-a.p1)*cross(a.p2-a.p1,b.p2-a.p1)<-eps &&
     cross(b.p2-b.p1,a.p1-b.p1)*cross(b.p2-b.p1,a.p2-b.p1)<-eps)
    return true;
  return false;
}

bool intersectLS(Line L,Segment s){
  return cross(L.p2-L.p1,s.p1-L.p1)*cross(L.p2-L.p1,s.p2-L.p1)<-eps;
}

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

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

int n,m;
Point s,ori(0,0);
vector<Point> g;
vector<Polygon> buildings;
vector<Point> vp;
vector<pid> e[MAX];

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

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

bool check(Point a){
  FOR(i,0,n)if(contains(buildings[i],a)==2)return false;
  return true;
}

bool check(Segment s){
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Point a=p[j],b=p[(j+1)%m],c=p[(j-1+m)%m];
      if(isParallel(Segment(a,b),s))continue;
      if(intersect(Segment(a,b),s))return false;
      if(ccw(s.p1,s.p2,a)==0 && !(s.p1==a) && !(s.p2==b)){
        if(ccw(s.p1,s.p2,b)*ccw(s.p1,s.p2,c)==-1)return false;
      }
    }
  }
  return true;
}

double getdis(Point a,Point b){
  Line L(s,b);
  Point c=project(L,a);
  if(ccw(s,b,c)==-2 && check(a+(c-a)/2.0) &&
     check(Segment(a,c)))return abs(c-a);
  c=Point(inf,inf);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Segment seg(p[j],p[(j+1)%m]);
      if(isParallel(L,seg))continue;
      if(!intersectLS(L,seg))continue;
      Point cp=getCrossPointLL(L,seg);
      if(ccw(s,b,cp)==-2 && abs(s-cp)<abs(s-c))c=cp;
    }
  }
  if(ccw(s,b,c)==-2 && check(a+(c-a)/2.0) &&
     check(Segment(a,c)))return abs(c-a);
  return inf;
}

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

  while(pq.size()){
    pdi u=pq.top();
    pq.pop();

    if(d[u.s]<u.f)continue;
    if(u.s==vp.size())return u.f;

    FOR(i,0,e[u.s].size()){
      int next=e[u.s][i].f;
      double cost=e[u.s][i].s+d[u.s];
      if(cost<d[next]){
        d[next]=cost;
        pq.push(mp(cost,next));
      }
    }
  }
  return inf;
}

double solve(){
  if(!check(Segment(ori,s)))return 0;
  vp.pb(ori);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      vp.pb(p[j]);
      if(ccw(s,p[j],p[(j-1+m)%m])*
         ccw(s,p[j],p[(j+1)%m])==1)g.pb(p[j]);
    }
  }
  
  FOR(i,0,vp.size()){
    FOR(j,i+1,vp.size()){
      if(check(vp[i]+(vp[j]-vp[i])/2.0) && 
         check(Segment(vp[i],vp[j])))add_edge(i,j,abs(vp[i]-vp[j]));
    }
  }
  FOR(i,0,vp.size()){
    double cost=inf;
    FOR(j,0,g.size()){
      if(vp[i]==g[j])cost=0;
      else cost=min(cost,getdis(vp[i],g[j]));
    }
    add_edge(vp.size(),i,cost);
  }
  return dijkstra();
}

int main()
{
  while(cin>>n && n){
    init();
    cin>>s.x>>s.y;
    FOR(i,0,n){
      cin>>m;
      Polygon p;
      FOR(j,0,m){
        int x,y;
        cin>>x>>y;
        p.pb(Point(x,y));
      }
      buildings.pb(p);
    }
    pd(solve());
  }
  return 0;
}
accuracy: 1
time_ms: 7270
memory_kb: 4956
final_rank: 20

code_snippet: #include<bits/stdc++.h>
#define MAX 1024
#define inf 1<<29
#define linf 1e16
#define eps (1e-8)
#define mod 1000000007
#define pi acos(-1)
#define phi (1.0+sqrt(5))/2.0
#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<int,double> pid;
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 equals(x,p.x) ? y-p.y<-eps : x-p.x<-eps; }
  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){}
};
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);}

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

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

bool intersect(Segment a,Segment b){
  if(cross(a.p2-a.p1,b.p1-a.p1)*cross(a.p2-a.p1,b.p2-a.p1)<-eps &&
     cross(b.p2-b.p1,a.p1-b.p1)*cross(b.p2-b.p1,a.p2-b.p1)<-eps)
    return true;
  return false;
}

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

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

int n,m;
Point s,ori(0,0);
vector<Point> g;
vector<Polygon> buildings;
vector<Point> vp;
vector<pid> e[MAX];

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

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

bool check(Point a){
  FOR(i,0,n)if(contains(buildings[i],a)==2)return false;
  return true;
}

bool check(Segment s){
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      Point a=p[j],b=p[(j+1)%m],c=p[(j-1+m)%m];
      if(isParallel(Segment(a,b),s))continue;
      if(intersect(Segment(a,b),s))return false;
      if(ccw(s.p1,s.p2,a)==0 && !(s.p1==a) && !(s.p2==b)){
        if(ccw(s.p1,s.p2,b)*ccw(s.p1,s.p2,c)==-1)return false;
      }
    }
  }
  return true;
}

double getdis(Point a,Point b){
  Point c=project(Line(s,b),a);
  if(abs(c-s)<abs(b-s))return inf;
  if(check(a+(c-a)/2.0),check(Segment(a,c)))return abs(c-a);
  return inf;
}

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

  while(pq.size()){
    pdi u=pq.top();
    pq.pop();

    if(d[u.s]<u.f)continue;
    if(u.s==vp.size())return u.f;

    FOR(i,0,e[u.s].size()){
      int next=e[u.s][i].f;
      double cost=e[u.s][i].s+d[u.s];
      if(cost<d[next]){
        d[next]=cost;
        pq.push(mp(cost,next));
      }
    }
  }
  return inf;
}

double solve(){
  if(!check(Segment(ori,s)))return 0;
  vp.pb(ori);
  FOR(i,0,n){
    Polygon p=buildings[i];
    m=p.size();
    FOR(j,0,m){
      vp.pb(p[j]);
      if(ccw(s,p[j],p[(j-1+m)%m])*
         ccw(s,p[j],p[(j+1)%m])==1)g.pb(p[j]);
    }
  }
  
  FOR(i,0,vp.size()){
    FOR(j,i+1,vp.size()){
      if(check(vp[i]+(vp[j]-vp[i])/2.0) && 
         check(Segment(vp[i],vp[j])))add_edge(i,j,abs(vp[i]-vp[j]));
    }
  }
  FOR(i,0,vp.size()){
    double cost=inf;
    FOR(j,0,g.size()){
      if(vp[i]==g[j])cost=0;
      else cost=min(cost,getdis(vp[i],g[j]));
    }
    add_edge(vp.size(),i,cost);
  }
  return dijkstra();
}

int main()
{
  while(cin>>n && n){
    init();
    cin>>s.x>>s.y;
    FOR(i,0,n){
      cin>>m;
      Polygon p;
      FOR(j,0,m){
        int x,y;
        cin>>x>>y;
        p.pb(Point(x,y));
      }
      buildings.pb(p);
    }
    pd(solve());
  }
  return 0;
}
accuracy: 1
time_ms: 5050
memory_kb: 4952
final_rank: 16

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

inline int sign(double x, double eps = 1e-8) {
	return x < -eps ? -1 : x > eps;
}

struct Point {
	double x, y;

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

	void in() {
		scanf("%lf%lf", &x, &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 * (const double &k) const {
		return Point(x * k, y * k);
	}

	Point operator / (const double &k) const {
		return Point(x / k, y / k);
	}

	double len() const {
		return sqrt(x * x + y * y);
	}

	double len2() const {
		return x * x + y * y;
	}
};

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

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

struct Segment {
	Point a, b;

	Segment(Point a = Point(0, 0), Point b = Point(0, 0)) : a(a), b(b) {}

	Point mid() const {
		return (a + b) / 2;
	}
};

bool parallel(const Segment &l0, const Segment &l1) {
	return sign(det(l0.b - l0.a, l1.b - l1.a)) == 0;
}

Point intersect(const Segment &l0, const Segment &l1) {
	double s0 = det(l1.a - l0.a, l0.b - l0.a),
		   s1 = det(l1.b - l0.a, l0.b - l0.a);
	return (l1.b * s0 - l1.a * s1) / (s0 - s1);
}

bool onLine(const Segment &l0, const Point &p) {
	return sign(det(p - l0.a, l0.b - l0.a)) == 0;
}

bool inSeg(const Segment &l0, const Point &p) {
	return sign(dot(p - l0.a, l0.b - l0.a)) > 0 && sign(dot(p - l0.b, l0.a - l0.b)) > 0;
}

bool onSeg(const Segment &l0, const Point &p) {
	return sign(dot(p - l0.a, l0.b - l0.a)) >= 0 && sign(dot(p - l0.b, l0.a - l0.b)) >= 0;
}

Point project(const Segment &l, const Point &p) {
	return l.a + (l.b - l.a) * dot(p - l.a, l.b - l.a) / (l.b - l.a).len2();
}

bool inside(const Point &q, const vector<Point> &p) {
	int cnt = 0;
	for (int i = 0; i < (int)p.size(); ++i) {
		Point a = p[i], b = p[(i + 1) % p.size()];
		if (onLine(Segment(a, b), q) && onSeg(Segment(a, b), q)) {
			return false;
		}
		if (sign(a.y - b.y) <= 0) {
			swap(a, b);
		}
		if (sign(q.y - a.y) > 0) {
			continue;
		}
		if (sign(q.y - b.y) <= 0) {
			continue;
		}
		cnt += sign(det(b - q, a - q)) > 0;
	}
	return cnt & 1;
}

int n;

vector<vector<Point> > polys;

bool legal(const Segment &s) {
	if (sign((s.b - s.a).len()) == 0) {
		return true;
	}
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < (int)polys[i].size(); ++j) {
			Segment l(polys[i][j], polys[i][(j + 1) % polys[i].size()]);
			if (parallel(s, l)) {
				continue;
			}
			Point p = intersect(s, l);
			if (inSeg(s, p) && onSeg(l, p)) {
				return false;
			}
		}
		if (inside(s.mid(), polys[i])) {
			return false;
		}
	}
	return true;
}

const double FAR = 1e6;

Point getSafe(const Point &p, const Point &b) {
	Point d = p - b;
	d = d / d.len();
	Segment s(p, p + d * FAR);
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < (int)polys[i].size(); ++j) {
			Segment l(polys[i][j], polys[i][(j + 1) % polys[i].size()]);
			if (parallel(s, l)) {
				continue;
			}
			Point p = intersect(s, l);
			if (inSeg(s, p) && onSeg(l, p)) {
				s.b = p;
			}
		}
		if (inside(s.mid(), polys[i])) {
			return p;
		}
	}
	return s.b;
}

const double INF = 1e9;

const int M = 505;

double g[M][M];

Point a, b;

int main() {
	while (scanf("%d", &n) == 1 && n) {
		a = Point(0, 0);
		b.in();
		vector<Point> ps;
		polys.clear();
		for (int i = 0; i < n; ++i) {
			int m;
			scanf("%d", &m);
			vector<Point> poly(m);
			for (int j = 0; j < m; ++j) {
				poly[j].in();
				ps.push_back(poly[j]);
			}
			polys.push_back(poly);
		}
		double ans = INF;
		if (!legal(Segment(a, b))) {
			ans = 0;
		} else {
			for (int i = 0; i <= ps.size(); ++i) {
				Point a = i ? ps[i - 1] : ::a;
				g[i][i] = 0;
				for (int j = i + 1; j <= ps.size(); ++j) {
					Point b = ps[j - 1];
					if (legal(Segment(a, b))) {
						g[i][j] = g[j][i] = (b - a).len();
					} else {
						g[i][j] = g[j][i] = INF;
					}
				}
			}
			for (int k = 0; k <= ps.size(); ++k) {
				for (int i = 0; i <= ps.size(); ++i) {
					for (int j = 0; j <= ps.size(); ++j) {
						g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
					}
				}
			}
			for (int i = 0; i < ps.size(); ++i) {
				Point block = ps[i];
				if (!legal(Segment(b, block))) {
					continue;
				}
				Segment safe(block, getSafe(block, b));
				if (sign((safe.b - safe.a).len()) == 0) {
					continue;
				}
				for (int j = 0; j <= (int)ps.size(); ++j) {	
					Point term = j ? ps[j - 1] : a,
						  target = project(safe, term);
					if (onSeg(safe, target) && legal(Segment(target, term))) {
						ans = min(ans, g[0][j] + (term - target).len());
					}
				}
			}
		}
		printf("%.12f\n", ans);
	}
	return 0;
}
accuracy: 1
time_ms: 7470
memory_kb: 3264
final_rank: 18

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

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

using namespace std;


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 a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

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

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

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

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

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

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

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

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

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

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

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

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

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

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

double distanceSS(Line s, Line t) {
  if (intersectSS(s, t)) return 0;
  return min(min(distanceSP(s, t.p1), distanceSP(s, t.p2)),
             min(distanceSP(t, s.p1), distanceSP(t, s.p2)));
}

Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if(abs(A) < EPS && abs(B) < EPS){
    vector<Point> vec;
    vec.push_back(l.p1),vec.push_back(l.p2),vec.push_back(m.p1),vec.push_back(m.p2);
    sort(vec.begin(),vec.end());
    assert(vec[1] == vec[2]); //???????????°??????????????????
    return vec[1];
    //return m.p1;
  }
  if(abs(A) < EPS)assert(false);
  return m.p1 + (m.p2-m.p1)*(B/A);
}


//cross product of pq and pr
double cross3p(Point p,Point q,Point r) { return (r.x-q.x) * (p.y -q.y) - (r.y - q.y) * (p.x - q.x); }
  
//returns true if point r is on the same line as the line pq
bool collinear(Point p,Point q,Point r) { return fabs(cross3p(p,q,r)) < EPS; }
  
//returns true if point t is on the left side of line pq
bool ccwtest(Point p,Point q,Point r){
  return cross3p(p,q,r) > 0; //can be modified to accept collinear points
}
 
bool onSegment(Point p,Point q,Point r){
  return collinear(p,q,r) && equals(sqrt(pow(p.x-r.x,2)+pow(p.y-r.y,2)) + sqrt(pow(r.x-q.x,2) + pow(r.y-q.y,2) ),sqrt(pow(p.x-q.x,2)+pow(p.y-q.y,2)) ) ;
}
  

double angle(Point a,Point b,Point c) {
  double ux = b.x - a.x, uy = b.y - a.y;
  double vx = c.x - a.x, vy = c.y - a.y;
  return acos((ux*vx + uy*vy)/sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)));
}  
  
//????§???¢poly?????????????????????????????????p????????¨??????????????????????????????  
bool inPolygon(Polygon poly,Point p,bool flag=true){
  if((int)poly.size() == 0)return false;
  if( flag ) rep(i,poly.size()) if(onSegment(poly[i],poly[(i+1)%poly.size()],p))return true;
  double sum = 0;
  for(int i=0; i < (int)poly.size() ;i++) {
    if( equals(cross(poly[i]-p,poly[(i+1)%poly.size()]-p),0.0) ) continue; // ????????????????????¨angle???nan?????????sum???nan??????????????¬
    if( cross3p(p,poly[i],poly[(i+1)%poly.size()]) < 0 ) sum -= angle(p,poly[i],poly[(i+1)%poly.size()]);
    else                                                 sum += angle(p,poly[i],poly[(i+1)%poly.size()]);
  }
  // ?????????????????????????????????????????¨?????????????????§??\????????????????????? 
  const double eps = 1e-5;
  return (fabs(sum - 2*M_PI) < eps || fabs(sum + 2*M_PI) < eps);
}  






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

bool LT(double a,double b) { return !equals(a,b) && a < b; }
bool LTE(double a,double b) { return equals(a,b) || a < b; }

bool DEBUG = false;

struct Data {
  Point cur;
  double weight;
  int a,b;
  bool operator < ( const Data &data ) const { return LT(data.weight,weight); }
};

const double DINF = 1e30;
int N;
Point bomb;
vector<Polygon> polies;
vector<vector<double> > mindist;
vector<vector<bool> > goals;

bool isValidMove(Point src,Point dst){

  Segment ururu_beam = Segment(src,dst);
  Point mp = ( src + dst ) * 0.5; // $
  rep(i,N) {
    int M = polies[i].size();
    bool in = false;
    bool on = false;
    rep(j,M) {
      Segment seg = Segment(polies[i][j],polies[i][(j+1)%M]);

      Point a = polies[i][j] - mp, b = polies[i][(j+1)%M] - mp;
      if( a.y > b.y ) swap(a,b);
      if( a.y <= 0 && 0 < b.y )  if( cross(a,b) < 0 ) in = !in;
      if( cross(a,b) == 0 && dot(a,b) <= 0 ) on = true;

      // ????????????????????¨??????????????§????????°???????§??????¶?????§?????£????????£???????§????
      if( equals(cross(ururu_beam.p1-ururu_beam.p2,seg.p1-seg.p2),0.0) ) continue;
      seg = Segment(polies[i][j],polies[i][(j-1+M)%M]);
      if( equals(cross(ururu_beam.p1-ururu_beam.p2,seg.p1-seg.p2),0.0) ) continue;
      seg = Segment(polies[i][j],polies[i][(j+1)%M]);

      if( !intersectSS(ururu_beam,seg) ) continue;

      Point cp = crosspoint(ururu_beam,seg);

      //????????? src or dst ??§????????´???????????£???????§????
      if( cp == ururu_beam.p1 || cp == ururu_beam.p2 ) continue;

      if( cp == seg.p1 || cp == seg.p2 ) {

	// p0 -> p1 ->p2, p0 -> p1 -> p3 ???????????§???????????¨????????? ( ?????§continue??????????????? )
	Point p0 = src;
	Point p1 = cp;
	Point p2 = polies[i][(j+1)%M];
	Point p3 = polies[i][(j-1+M)%M];
	if( cp == p2 || cp == p3 ) continue;
	int ccw_res1 = ccw(p0,p1,p2);
	int ccw_res2 = ccw(p0,p1,p3);
	if( ccw_res1 != ccw_res2 ) return false;
      } else return false;
    }
    if( !( src == bomb || dst == bomb ) && !on && in ) return false;
  }


  /*
  if( !( src == bomb || dst == bomb ) ) {
    Point mp = ( src + dst ) / 2.0;
    //rep(i,N) if( inPolygon(polies[i],mp,false) ) return false;
    rep(i,N) if( contains(polies[i],mp) == IN ) return false;
  }
  */

  return true;
}

double temper;
void dijkstra(){
  temper = DINF;
  priority_queue<Data> Q;
  Q.push((Data){(Point){0,0},0,-1,-1});
  while( !Q.empty() ){  
    Data data = Q.top(); Q.pop();
    if( data.a != -1 && LT(mindist[data.a][data.b],data.weight) ) continue;
    if( data.a != -1 && goals[data.a][data.b] ) {
      temper = data.weight;
      return;
    }
    rep(i,N) rep(j,polies[i].size()){
      Point next = polies[i][j];
      if( data.cur == next ) continue;
      if( !isValidMove(data.cur,next) ) continue;
      double next_weight = data.weight + abs(next-data.cur);
      if( LT(next_weight,mindist[i][j]) ) {
	mindist[i][j] = next_weight;
	Q.push((Data){next,next_weight,i,j});
      }
    }
  }
}

//???????????¶?´??????????ururu_beam??¨seg???????????§???????????¨?????????
bool isGoal(Point p){
  Segment ururu_beam = Segment(bomb,p);
  rep(i,N){
    int M = polies[i].size();
    rep(j,M){
      Segment seg = Segment(polies[i][j],polies[i][(j+1)%M]);
      if( !intersectSS(ururu_beam,seg) ) continue;
      Point cp = crosspoint(ururu_beam,seg);

      if( !( cp == p ) ) return true;
      else if( cp == seg.p1 || cp == seg.p2 ) {
	int k = (cp==seg.p1?j:(j+1)%M);
	int c1 = ccw(bomb,p,polies[i][(k-1+M)%M]);
	int c2 = ccw(bomb,p,polies[i][(k+1)%M]);
	assert( !( p == polies[i][(k-1+M)%M]));
	assert( !( p == polies[i][(k+1)%M]));
	assert( c1 == COUNTER_CLOCKWISE || c1 == CLOCKWISE );
	assert( c2 == COUNTER_CLOCKWISE || c2 == CLOCKWISE );
	if( c1 == c2 ) return true;
      }
    }
  }
  return false;
}

//????????¨?????????????????§??????????????¨???????¨????????????????
Point getOnSegmentPoint(Point p){
  Segment ururu_beam = Segment(bomb,p);
  Vector e = (ururu_beam.p2-ururu_beam.p1) / abs(ururu_beam.p2-ururu_beam.p1);
  ururu_beam.p2 = bomb + e * 1000000;
  Point ret = Point(-DINF,-DINF);
  rep(i,N) {
    int M = polies[i].size();
    rep(j,M){
      Segment seg = Segment(polies[i][j],polies[i][(j+1)%M]);
      if( !intersectSS(ururu_beam,seg) ) continue;
      Point cp = crosspoint(ururu_beam,seg);
      if( cp == p ) continue;
      if( ret == Point(-DINF,-DINF) ) ret = cp;
      else if( LT(abs(cp-bomb),abs(ret-bomb)) ) ret = cp;
    }
  }
  return ret;
}

Point vir;
bool comp_dist(const Point &p,const Point &q) {
  return LT(abs(vir-p),abs(vir-q));
}

void compute(){


  if( isGoal(Point(0,0)) ) {
    printf("%.10f\n",0.0);
    return;
  }

  rep(i,N) rep(j,polies[i].size()) goals[i][j] = isGoal(polies[i][j]);

  // dijkstra ??§??????????????????????????¢????±???????
  dijkstra();


  //rep(i,N) rep(j,polies[i].size()) goals[i][j] = isGoal(polies[i][j]);
  //double answer = DINF;
  double answer = temper;
  rep(i,N) rep(j,polies[i].size()) if( goals[i][j] && LT(mindist[i][j],answer) ) {
    answer = mindist[i][j];
  }

  // ??´????????¨??????????£?????????????
  // ???????????????????????´??????????????´????????§????????°????°?????????´??°??????
  rep(i,N) {
    int M = polies[i].size();
    rep(j,M){
      Point p0 = bomb;
      Point p1 = polies[i][j];
      Point p2 = polies[i][(j+1)%M];
      Point p3 = polies[i][(j-1+M)%M];
      int ccw_res1 = ccw(p0,p1,p2);
      int ccw_res2 = ccw(p0,p1,p3);
      if( ( ccw_res1 == COUNTER_CLOCKWISE || ccw_res1 == CLOCKWISE ) && ( ccw_res2 == COUNTER_CLOCKWISE || ccw_res2 == CLOCKWISE ) && ccw_res1 != ccw_res2 ) {
	continue;
      }

      //?????????????§???¢????§?????????????????????¶?????????????????????
      //?????????
      Point p = getOnSegmentPoint(polies[i][j]);
      if( p.x != -DINF && p.y != -DINF ) {
	//if( !( LT(abs(p),answer) ) )
	if( isGoal(p) )	{
	  if( LT(abs(p),answer) && isValidMove(Point(0,0),p) ) {
	    answer = min(answer,abs(p));
	  } else {
	    double mini = DINF;
	    rep(k,N) rep(l,polies[k].size()) if( LT(mindist[k][l]+abs(polies[k][l]-p),min(answer,mini)) && isValidMove(polies[k][l],p) ) {
	      mini = min(mini,mindist[k][l]+abs(polies[k][l]-p));
	    }
	    answer = min(answer,mini);
	  }
	}
      }

      //?????´
      p = projection(Segment(bomb,polies[i][j]),Point(0,0));

      //if( !( LT(abs(p),answer) ) )
      if( isGoal(p) )	{
	if( isValidMove(Point(0,0),p) ) {
	  answer = min(answer,abs(p));
	} else {
	  bool success = true;
	  Segment ururu_beam = Segment(p,Point(0,0));
	  rep(k,N) {
	    int M2 = polies[k].size();
	    rep(l,M2){
	      Segment seg = Segment(polies[k][l],polies[k][(l+1)%M2]);
	      if( !intersectSS(ururu_beam,seg) ) continue;
	      if( equals(cross(ururu_beam.p1-ururu_beam.p2,seg.p1-seg.p2),0.0) ) continue;
	      Point cp = crosspoint(ururu_beam,seg);
	      if( cp == seg.p1 || cp == seg.p2 || cp == ururu_beam.p1 || cp == ururu_beam.p2 ) continue;
	      success = false;
	      break;
	    }
	    if( !success ) break;
	  }
	  if( success ) {
	    double mini = DINF;
	    rep(k,N) rep(l,polies[k].size()) if( goals[k][l] ) {
	    mini = min(mini,mindist[k][l]+abs(ururu_beam.p1-ururu_beam.p2));
	    }
	  }
	}
      }
    }
  }

  printf("%.10f\n",answer);
  
}

int main(){
  while( scanf("%d",&N) , N ) {
    polies.clear(), mindist.clear(); goals.clear();
    polies.resize(N), mindist.resize(N), goals.resize(N);
    //cin >> bomb.x >> bomb.y;
    scanf("%lf %lf",&bomb.x,&bomb.y);
    rep(i,N) {
      int m;
      scanf("%d",&m);
      polies[i].resize(m), mindist[i].resize(m,DINF), goals[i].resize(m,false);
      rep(j,m) scanf("%lf %lf",&polies[i][j].x,&polies[i][j].y);//cin >> polies[i][j].x >> polies[i][j].y;
    }
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 3260
memory_kb: 1348
final_rank: 5

code_snippet: #include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const double EPS = 1e-7;
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{ return !sig(x-a.x)&&!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; }
};
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;
}
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 iLS(Pt a, Pt b, Pt c, Pt d) {
	return (sig(tri(a, b, c)) * sig(tri(a, b, d)) <= 0);
}
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 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);
}
Pt hLP(Pt a,Pt b,Pt c){
	return pLL(a,b,c,c+(b-a)*Pt(0,1));
}
double dLP(Pt a, Pt b, Pt c) {
	return ABS(tri(a, b, c)) / (b - a).ABS();
}
double dSP(Pt a, Pt b, Pt c) {
	if (sig((b - a).dot(c - a)) <= 0) return (c - a).ABS();
	if (sig((a - b).dot(c - b)) <= 0) return (c - b).ABS();
	return ABS(tri(a, b, c)) / (b - a).ABS();
}
double dLL(Pt a, Pt b, Pt c, Pt d) {
	return iLL(a, b, c, d) ? 0 : dLP(a, b, c);
}
double dLS(Pt a, Pt b, Pt c, Pt d) {
	return iLS(a, b, c, d) ? 0 : min(dLP(a, b, c), dLP(a, b, d));
}
double dSS(Pt a, Pt b, Pt c, Pt d) {
	return iSS(a, b, c, d) ? 0 : min(min(dSP(a, b, c), dSP(a, b, d)), min(dSP(c, d, a), dSP(c, d, b)));
}
int convexCut(int n, Pt p[], Pt a, Pt b, Pt q[]) {
	int m = 0, i;
	p[n] = p[0];
	for (i = 0; i < n; ++i) {
		if (sig(tri(a, b, p[i])) >= 0) q[m++] = p[i];
		if (sig(tri(a, b, p[i])) * sig(tri(a, b, p[i + 1])) < 0) q[m++] = pLL(a, b, p[i], p[i + 1]);
	}
	q[m] = q[0];
	return m;
}
int iCC(Pt a, double r, Pt b, double s) {
	double d = (b - a).ABS();
	if (sig(d) == 0 && sig(r - s) == 0) return -1; // correspond
	if (sig(r - s - d) > 0) return +2; // r > s
	if (sig(s - r - d) > 0) return -2; // s > r
	return (sig(r + s - d) >= 0) ? 1 : 0;
}
bool iCS(Pt a, double r, Pt b, Pt c) {
	return (sig(r - dSP(b, c, a)) >= 0 && sig(r - max((b - a).ABS(), (c - a).ABS())) <= 0);
}
pair<Pt,Pt> pCC(Pt a, double r, Pt b, double s) {
	double d = (b - a).ABS();
	double x = (d * d + r * r - s * s) / (d * 2);
	Pt e = (b - a) / d, w = e * Pt(0, 1) * sqrt(max(r * r - x * x, 0.0));
	return make_pair(a + e * x - w, a + e * x + w);
}
pair<Pt,Pt> pCL(Pt a, double r, Pt b, Pt c) {
	Pt h = b + (c - b) * (c - b).dot(a - b) / (c - b).abs2(); // perp(b, c, a)
	double d = (h - a).ABS();
	double y = sqrt(max(r * r - d * d, 0.0));
	Pt e = (c - b) / (c - b).ABS();
	return make_pair(h - e * y, h + e * y);
}
pair<Pt,Pt> tCP(Pt a, double r, Pt b) {
	double d2 = (b - a).abs2();
	double x = sqrt(max(d2 - r * r, 0.0));
	Pt h = a + (b - a) * (r * r / d2);
	Pt w = (b - a) * Pt(0, 1) * (x * r / d2);
	return make_pair(h - w, h + w);
}
double aCC(Pt a, double r, Pt b, double s) {
	double d = (a - b).ABS();
	if (sig(r - s - d) >= 0) return s * s * PI;
	if (sig(s - r - d) >= 0) return r * r * PI;
	if (sig(r + s - d) <= 0) return 0;
	double x = (d * d + r * r - s * s) / (d * 2);
	double h = sqrt(r * r - x * x);
	return r * r * atan2(h, x) + s * s * atan2(h, d - x) - d * h;
}
//inside: +1 on: 0 outside: -1
int sGP(int n, Pt p[], Pt a) {
	int side = -1, i;
	p[n] = 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;
}
int sAP(Pt a, Pt b, Pt c) {
	return sig(a.det(c)) - sig(b.det(c)) - sig(a.det(b));
}

int s_a[1100], s_b[1100], s_ab[1100];
bool iGSstrict(vector<Pt> p, Pt a, Pt b) {
	int i;
	int n=p.size();
	p.push_back(p[0]);
	p.push_back(p[1]);
//	if (sGP(n, p, a) > 0 || sGP(n, p, b) > 0) return 1;
	for (i = 0; i <= n; ++i) {
		s_a[i] = sig(tri(p[i], p[i + 1], a));
		s_b[i] = sig(tri(p[i], p[i + 1], b));
		s_ab[i] = sig(tri(a, b, p[i]));
	}
	for (i = 0; i < n; ++i) {
		if (s_a[i] * s_b[i] < 0 && s_ab[i] * s_ab[i + 1] < 0) return 1;
	}
	for (i = 0; i < n; ++i) {
		if (s_a[i] == 0 && s_b[i] > 0 && sig((a - p[i]).dot(a - p[i + 1])) < 0) return 1;
		if (s_b[i] == 0 && s_a[i] > 0 && sig((b - p[i]).dot(b - p[i + 1])) < 0) return 1;
	}
	for (i = 0; i < n; ++i) if (s_ab[i + 1] == 0 && sig((p[i + 1] - a).dot(p[i + 1] - b)) <= 0) {
		if (!(p[i + 1] == a) && sAP(p[i + 2] - p[i + 1], p[i] - p[i + 1], a - p[i + 1]) > 0) return 1;
		if (!(p[i + 1] == b) && sAP(p[i + 2] - p[i + 1], p[i] - p[i + 1], b - p[i + 1]) > 0) return 1;
	}
	return 0;
}
vector<Pt>p[110];
vector<Pt>q;
vector<pair<Pt,Pt> > edge;
double ijk[110000];
int v[110000];
int main(){
	int a;
	while(scanf("%d",&a),a){
		double bx,by;scanf("%lf%lf",&bx,&by);
		Pt bm=Pt(bx,by);
		for(int i=0;i<a;i++)p[i].clear();
		for(int i=0;i<a;i++){
			int c;scanf("%d",&c);
			for(int j=0;j<c;j++){
				double ix,iy;
				scanf("%lf%lf",&ix,&iy);
				p[i].push_back(Pt(ix,iy));
			}
		}
		bool zr=false;
		for(int i=0;i<a;i++){
			for(int j=0;j<p[i].size();j++){
				if(iSSstrict(p[i][j],p[i][(j+1)%p[i].size()],Pt(0,0),bm))zr=true;
			}
		}
		if(zr){
			printf("%.12f\n",0.0);
			continue;
		}
		q.clear();
		edge.clear();
		q.push_back(Pt(0,0));
		for(int i=0;i<a;i++){
			for(int j=0;j<p[i].size();j++){
				Pt r=bm+(p[i][j]-bm)*1000000;
				bool tc=false;
				for(int k=0;k<a;k++)for(int l=0;l<p[k].size();l++){
					if(iSSstrict(p[k][l],p[k][(l+1)%p[k].size()],p[i][j],r)){
						r=pLL(p[k][l],p[k][(l+1)%p[k].size()],p[i][j],r);
					}
					if(iSSstrict(p[k][l],p[k][(l+1)%p[k].size()],bm,p[i][j])){
						tc=true;break;
					}
				}
				if(tc)continue;
				q.push_back(p[i][j]);
				if(r.ABS()<100000)q.push_back(r);
				if(!iGSstrict(p[i],p[i][j],r))edge.push_back(make_pair(p[i][j],r));
			}
		}
		
		int n=q.size();
		for(int i=0;i<n;i++)ijk[i]=999999999;
		for(int i=0;i<n;i++)v[i]=0;
		ijk[0]=0;
		for(int i=0;i<n;i++){
			double best=99999999;
			int at=-1;
			for(int j=0;j<n;j++){
				if(!v[j]&&best>ijk[j]){
					best=ijk[j];
					at=j;
				}
			}
			if(!~at)break;
			v[at]=1;
			for(int j=0;j<n;j++){
				if(v[j]||ijk[at]+(q[at]-q[j]).ABS()+EPS>ijk[j])continue;
				bool ok=true;
				for(int k=0;k<a;k++){
					if(iGSstrict(p[k],q[at],q[j])){ok=false;break;}
				}
				if(ok){
					ijk[j]=min(ijk[j],ijk[at]+(q[at]-q[j]).ABS());
				}
			}
		}
		double ret=999999999;
		//for(int i=0;i<edge.size();i++)printf("(%f %f), (%f %f)\n",edge[i].first.x,edge[i].first.y,edge[i].second.x,edge[i].second.y);
		for(int i=0;i<n;i++){
			for(int j=0;j<edge.size();j++){
				Pt L=edge[j].first;
				Pt R=edge[j].second;
				Pt H=hLP(edge[j].first,edge[j].second,q[i]);
				bool ok;
				ok=true;
				if(ret<EPS+ijk[i]+(q[i]-L).ABS())ok=false;
				for(int k=0;ok&&k<a;k++)if(iGSstrict(p[k],q[i],L)){ok=false;break;}
				if(ok)ret=min(ret,ijk[i]+(q[i]-L).ABS());
				ok=true;
				if(ret<EPS+ijk[i]+(q[i]-R).ABS())ok=false;
				for(int k=0;ok&&k<a;k++)if(iGSstrict(p[k],q[i],R)){ok=false;break;}
				if(ok)ret=min(ret,ijk[i]+(q[i]-R).ABS());
				ok=true;
				if(ret<EPS+ijk[i]+(q[i]-H).ABS())ok=false;
				for(int k=0;ok&&k<a;k++)if(iGSstrict(p[k],q[i],H)){ok=false;break;}
				if(ok&&iSP(L,H,R)==2){
					ret=min(ret,ijk[i]+(q[i]-H).ABS());
				}
			}
		}
		printf("%.12f\n",ret);
	}
}
accuracy: 1
time_ms: 1110
memory_kb: 1196
final_rank: 1

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 <unordered_map>
#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 long double R;
	const R INF = 1e8;
	R EPS = 1e-6;
	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;
			// テ・ツコツァテヲツィツ凖」ツ?ョテ、ツコツ古、ツケツ療」ツ?ィEPSテ」ツ?ョテ・ツキツョテ」ツ?古・ツ、ツァテ」ツ?催」ツ?凖」ツ?偲」ツ?ェテ」ツ??」ツつ暗」ツ??」ツ?ォテヲツウツィテヲツ??
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//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));}
	};

	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 (R)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 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;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
}
int n;

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> n, n){
		P p;
		cin >> p;
		vector<G> g(n);
		REP(i, n){
			int x;
			cin >> x;
			g[i].resize(x);
			REP(j, x){
				cin >> g[i][j];
				g[i][j] -= p;
			}
		}
		p = -p;
		if([&](){
			REP(i, n)REP(j, g[i].size()){
				if(intersect(g[i].edge(j), S(0, p)) == TRUE) return 1;
			}
			return 0;
		}()){
			printf("%.10f\n", .0);
			continue;
		}
		
		vector<S> acc;
		REP(i, n)REP(j, g[i].size()){
			L s(0, unit(g[i][j]));
			if(ccw(0, s[1], g[i][(j+1)%g[i].size()]) != ccw(0, s[1], g[i][(j-1+g[i].size())%g[i].size()])) continue;
			R from = abs(g[i][j]), to = 20000;
			REP(ii, n)REP(jj, g[ii].size()){
				S t = g[ii].edge(jj);
				if(!sig(outp(s.dir(), t.dir())) || intersect(t, s) != TRUE) continue;
				P p = crosspoint(s, t);
				if(inp(s.dir(), p) > 0){
					to = min(to, abs(p));
				}
			}
			if(from < to) acc.emplace_back(s[1]*from, s[1]*to);
		}
		auto cango = [&](const P &s, const P &t){
			const S root(s, t);
			REP(i, n)REP(j, g[i].size()){
				const S edge = g[i].edge(j);
				if(sig(outp(root.dir(), edge.dir())) && intersect(root, edge) == TRUE) return 0;
			}
			return 1;
		};
		
		struct State{
			int x, y;
			R cost;
			State (int x, int y, R cost)
				:x(x), y(y), cost(cost){}
			bool operator<(const State &opp) const{
				return cost > opp.cost;
			}
		};
		vector<vector<R>> visited(n, vector<R>(101, INF));
		priority_queue<State> pq;
		pq.emplace(-1, -1, 0);
		R ans = INF;
		while(!pq.empty()){
			State s = pq.top(); pq.pop();
			P q = (s.x == -1) ? p : g[s.x][s.y];
			if(s.cost > ans) break;
			if(s.x >= 0 && visited[s.x][s.y] < s.cost - EPS) continue;
			FOR(it, acc){
				P pr = proj(q, *it);
				if(inp(pr - (*it)[0], it->dir()) < EPS) pr = (*it)[0];
				else if(inp(pr - (*it)[1], -it->dir()) < EPS) pr = (*it)[1];
				if(s.cost + abs(q - pr) < ans - EPS && cango(q, pr)){
					ans = s.cost + abs(q - pr);
				}
			}
			REP(i, n)REP(j, g[i].size()){
				R c = s.cost + abs(g[i][j] - q);
				if(c+EPS > visited[i][j]) continue;
				if(cango(q, g[i][j])){
					visited[i][j] = c;
					pq.emplace(i, j, c);
				}
			}
		}
		printf("%.10f\n", (double)ans);
	}
	return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 1488
final_rank: 2

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 <unordered_map>
#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 long double R;
	const R INF = 1e8;
	R EPS = 1e-6;
	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;
			// 座標の二乗とEPSの差が大きすぎないように注意
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//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));}
	};

	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 (R)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 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;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
}
int n;

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> n, n){
		P p;
		cin >> p;
		vector<G> g(n);
		REP(i, n){
			int x;
			cin >> x;
			g[i].resize(x);
			REP(j, x){
				cin >> g[i][j];
				g[i][j] -= p;
			}
		}
		p = -p;
		if([&](){
			REP(i, n)REP(j, g[i].size()){
				if(intersect(g[i].edge(j), S(0, p)) == TRUE) return 1;
			}
			return 0;
		}()){
			printf("%.10f\n", .0);
			continue;
		}
		
		vector<S> acc;
		REP(i, n)REP(j, g[i].size()){
			L s(0, unit(g[i][j]));
			if(ccw(0, s[1], g[i][(j+1)%g[i].size()]) != ccw(0, s[1], g[i][(j-1+g[i].size())%g[i].size()])) continue;
			R from = abs(g[i][j]), to = 20000;
			REP(ii, n)REP(jj, g[ii].size()){
				S t = g[ii].edge(jj);
				if(!sig(outp(s.dir(), t.dir())) || intersect(t, s) != TRUE) continue;
				P p = crosspoint(s, t);
				if(inp(s.dir(), p) > 0){
					to = min(to, abs(p));
				}
			}
			if(from < to) acc.emplace_back(s[1]*from, s[1]*to);
		}
		auto cango = [&](const P &s, const P &t){
			const S root(s, t);
			REP(i, n)REP(j, g[i].size()){
				const S edge = g[i].edge(j);
				if(sig(outp(root.dir(), edge.dir())) && intersect(root, edge) == TRUE) return 0;
			}
			return 1;
		};
		
		struct State{
			int x, y;
			R cost;
			State (int x, int y, R cost)
				:x(x), y(y), cost(cost){}
			bool operator<(const State &opp) const{
				return cost > opp.cost;
			}
		};
		vector<vector<R>> visited(n, vector<R>(101, INF));
		priority_queue<State> pq;
		pq.emplace(-1, -1, 0);
		R ans = INF;
		while(!pq.empty()){
			State s = pq.top(); pq.pop();
			P q = (s.x == -1) ? p : g[s.x][s.y];
			if(s.cost > ans) break;
			if(s.x >= 0 && visited[s.x][s.y] < s.cost - EPS) continue;
			FOR(it, acc){
				P pr = proj(q, *it);
				if(inp(pr - (*it)[0], it->dir()) < EPS) pr = (*it)[0];
				else if(inp(pr - (*it)[1], -it->dir()) < EPS) pr = (*it)[1];
				if(s.cost + abs(q - pr) < ans - EPS && cango(q, pr)){
					ans = s.cost + abs(q - pr);
				}
			}
			REP(i, n)REP(j, g[i].size()){
				R c = s.cost + abs(g[i][j] - q);
				if(c+EPS > visited[i][j]) continue;
				if(cango(q, g[i][j])){
					visited[i][j] = c;
					pq.emplace(i, j, c);
				}
			}
		}
		printf("%.10f\n", (double)ans);
	}
	return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 1488
final_rank: 2

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 <unordered_map>
#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 long double R;
	const R INF = 1e8;
	R EPS = 1e-6;
	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;
			// 座標の二乗とEPSの差が大きすぎないように注意
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//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.);
		}
		P gp()const {
			P r(.0, .0);
			REP(i, size()){
				const S &s = edge(i);
				r += (s[0]+s[1])*outp(s[0], s[1]);
			}
			return r / (6*area());
		}
		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])*(R)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 (R)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(max<R>(0., 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(max<R>(.0, 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;
		R d = abs(a-b);
		R rc = (d*d + a.r*a.r - b.r*b.r) / (2*d);
		R theta = acos(rc / a.r);
		R 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);
		R 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);
			R rad = asin(c1.r/abs(crs-c1));
			res.push_back(L(crs, crs + (c1-crs)*polar((R)1, rad)));
			res.push_back(L(crs, crs + (c1-crs)*polar((R)1, -rad)));
		}
		if(c1.r + d + EPS > c2.r){
			// 外接線
			R rad = 0.5*PI+asin((c2.r-c1.r) / d);
			P v = unit(c2-c1)*polar((R)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 = (R)2.*proj(v, c2-c1) - v;
				res.push_back(L(c1+v*c1.r, c2+v*c2.r));
			}
		}
		return res;
	}
	
	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]*(R).5;
				r[m] = r[m-1] + e*e/z[m]*(R).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);
		}
	};
	
	template<class T> vector<T> merge(vector<T> s) {
		REP(i, s.size()) if (s[i][1] < s[i][0]) swap(s[i][0], s[i][1]);
		sort(ALL(s));
		REP(i, s.size())REP(j, i)if(intersect(s[i], s[j]) && !sig(outp(s[i].dir(), s[j].dir()))) {
			s[j][1] = max(s[i][1], s[j][1]);
			s.erase(s.begin() + i--);
			break;
		}
		return s;
	}

#undef SELF
#undef at
}

using namespace geom;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	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 R B = 500;
	const R Z = 5;
	ostream& operator<<(ostream &os, const C &c){return os << "circle("<<B+Z*(c.X)<<", "<<1000-B-Z*(c.Y)<<", "<<Z*(c.r)<<")";}
	ostream& operator<<(ostream &os, const P &p){return os << C(p, 2./Z);}
	ostream& operator<<(ostream &os, const S &s){return os << "line("<<B+Z*(s[0].X)<<", "<<1000-B-Z*(s[0].Y)<<", "<<B+Z*(s[1].X)<<", "<<1000-B-Z*(s[1].Y)<<")";}
	ostream& operator<<(ostream &os, const G &g){REP(i, g.size()) os << g.edge(i) << endl;return os;}

}
int n;

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> n, n){
		P p;
		cin >> p;
		vector<G> g(n);
		REP(i, n){
			int x;
			cin >> x;
			g[i].resize(x);
			REP(j, x){
				cin >> g[i][j];
				g[i][j] -= p;
			}
		}
		p = -p;
		if([&](){
			REP(i, n)REP(j, g[i].size()){
				if(intersect(g[i].edge(j), S(0, p)) == TRUE) return 1;
			}
			return 0;
		}()){
			printf("%.10f\n", .0);
			continue;
		}
		
		vector<S> acc;
		REP(i, n)REP(j, g[i].size()){
			L s(0, unit(g[i][j]));
			if(ccw(0, s[1], g[i][(j+1)%g[i].size()]) != ccw(0, s[1], g[i][(j-1+g[i].size())%g[i].size()])) continue;
			R from = abs(g[i][j]), to = 20000;
			REP(ii, n)REP(jj, g[ii].size()){
				S t = g[ii].edge(jj);
				if(!sig(outp(s.dir(), t.dir())) || intersect(t, s) != TRUE) continue;
				P p = crosspoint(s, t);
				if(inp(s.dir(), p) > 0){
					to = min(to, abs(p));
				}
			}
			if(from < to) acc.emplace_back(s[1]*from, s[1]*to);
		}
		auto cango = [&](const P &s, const P &t){
			const S root(s, t);
			REP(i, n)REP(j, g[i].size()){
				const S edge = g[i].edge(j);
				if(sig(outp(root.dir(), edge.dir())) && intersect(root, edge) == TRUE) return 0;
			}
			return 1;
		};
		
		struct State{
			int x, y;
			R cost;
			State (int x, int y, R cost)
				:x(x), y(y), cost(cost){}
			bool operator<(const State &opp) const{
				return cost > opp.cost;
			}
		};
		vector<vector<R>> visited(n, vector<R>(101, INF));
		priority_queue<State> pq;
		pq.emplace(-1, -1, 0);
		R ans = INF;
		while(!pq.empty()){
			State s = pq.top(); pq.pop();
			P q = (s.x == -1) ? p : g[s.x][s.y];
			if(s.cost > ans) break;
			if(s.x >= 0 && visited[s.x][s.y] < s.cost - EPS) continue;
			FOR(it, acc){
				P pr = proj(q, *it);
				if(inp(pr - (*it)[0], it->dir()) < EPS) pr = (*it)[0];
				else if(inp(pr - (*it)[1], -it->dir()) < EPS) pr = (*it)[1];
				if(s.cost + abs(q - pr) < ans - EPS && cango(q, pr)){
					ans = s.cost + abs(q - pr);
				}
			}
			REP(i, n)REP(j, g[i].size()){
				R c = s.cost + abs(g[i][j] - q);
				if(c+EPS > visited[i][j]) continue;
				if(cango(q, g[i][j])){
					visited[i][j] = c;
					pq.emplace(i, j, c);
				}
			}
		}
		printf("%.10f\n", (double)ans);
	}
	return 0;
}
accuracy: 1
time_ms: 950
memory_kb: 1520
final_rank: 4