#include<complex>
#include<vector>
#include<iostream>
#include<stack>
#include<cmath>
#include<queue>
#include<fstream>
#include<functional>
#include<cstdio>
#include<set>
#include<cassert>


#define FRONT 0x01
#define RIGHT 0x02
#define BACK 0x04
#define LEFT 0x08
#define OVER 0x10

#define sc second
#define fr first

using namespace std;

typedef double elem;
typedef complex<elem> point, vec;
typedef pair<point, point> line, hline, seg, pp;

const double infty = 1e40;
const double eps = 1.0e-8;
const double pi = acos(-1.0);
//ofstream vis("vis.txt");

bool eq(elem a, elem b){ return abs(a-b) < eps; }
bool eqv(const vec &a, const vec &b){ return eq( abs(b-a),0); }
bool far(const point &a, const point &b){ return abs(b-a)>0; }
bool near(const point &a, const point &b){ return abs(b-a)<=0; }
elem dot(const vec &a, const vec &b){ return (a.real() * b.real() + a.imag() * b.imag() ); }
elem cross(const vec &a, const vec &b){ return ( a.real() * b.imag() - a.imag() * b.real() ); }
vec uvec(const vec &a){ return a / abs(a); }
vec nmr(const vec &a){ return a * vec(0,-1); }
vec nml(const vec &a){ return a * vec(0,1); }
vec unmr(const vec &a){ return uvec( nmr(a) ); }
vec unml(const vec &a){ return uvec( nml(a) ); }
//inline elem arg(const vec &a, const vec &b){ return acos( dot(a,b) / ( abs(a) * abs(b) ) ); }
elem dist_l(const line &l, const point &x){ return abs(cross(l.sc-l.fr,x-l.fr)) / abs(l.sc-l.fr); }
bool over(const point &a, const point &b, const point &c){
  return eq(abs(b-a),abs(a-c)+abs(b-c));
}
inline elem varg(const vec &a, const vec &b){
  elem ret=arg(a)-arg(b);
  if(ret<0)ret+=2*pi;
  if(ret>2*pi)ret-=2*pi;
  if(eq(ret,2*pi))ret=0;
  return ret;
}
inline elem varg2(const vec &a, const vec &b){
  elem ret=varg(a,b);
  return (ret>pi)?2*pi-ret:ret;
}
inline int ccw(point a, point b, point x){
  b -= a;
  x -= a;
  if( eq(cross(b,x),0.0) && dot(b,x) < 0 ) return BACK;
  if( eq(cross(b,x),0.0) && abs(b) < abs(x) ) return FRONT;
  if( eq(cross(b,x),0.0) ) return OVER;
  if( cross(b,x) > 0 ) return LEFT;
  if( cross(b,x) < 0 ) return RIGHT;
}

inline bool intersectedSS(const seg &a, const seg &b)
{
  if( ccw(a.fr,a.sc,b.fr)==OVER || ccw(a.fr,a.sc,b.sc)==OVER ||
      ccw(b.fr,b.sc,a.fr)==OVER || ccw(b.fr,b.sc,a.sc)==OVER ) return true;
  return
    ( ccw(a.fr,a.sc,b.fr) | ccw(a.fr,a.sc,b.sc) ) == (LEFT|RIGHT) &&
    ( ccw(b.fr,b.sc,a.fr) | ccw(b.fr,b.sc,a.sc) ) == (LEFT|RIGHT) ;
}

bool intersectedLL(const line &a, const line &b){ return !eq( cross(a.sc-a.fr,b.sc-b.fr), 0.0 ); }

point intersectionSS(const seg &a, const seg &b)
{
  elem d1 = dist_l(b,a.fr);
  elem d2 = dist_l(b,a.sc);
  return a.fr + ( d1 / (d1 + d2 ) ) * (a.sc-a.fr);
}
point intersectionLL(const line &a, const line &b)
{
  vec va = a.sc - a.fr;
  vec vb = b.sc - b.fr;
  return a.fr + va * ( cross(vb, b.fr - a.fr) / cross(vb,va) );
}

bool intersectionLL(const line &a, const line &b, point &ret){
  return intersectedLL( a, b ) ? ret = intersectionLL( a, b ), true : false;
}
bool intersectionLH(const line &a, const hline &b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret=tmp, true : false ) : false;
}
bool intersectionLS(const line &l, const seg &s, point &ret){
  point tmp;
  return intersectionLL(l,s,tmp) ? ( ccw(s.fr,s.sc,tmp)&OVER ? ret=tmp, true : false ) : false;
}
bool intersectionHH(const hline &a, const hline &b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT)&&ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
bool intersectionHS(const hline &a, const seg &s, point &ret){
  point tmp;
  return intersectionLS(a,s,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
inline bool intersectionSS(const seg &a, const seg &b, point &ret){
  return intersectedSS(a,b) ? ret = intersectionSS(a,b), true : false;
}

// P½p`Ìàï»è(«EüÜÜÈ¢)
bool inSimple(const point &x, int n, point p[])
{
  int cnt=0;
  for(int i = 0; i < n; ++i){
    point a=p[i]-x,b=p[(i+1)%n]-x;
    if(b.imag()>a.imag())swap(a,b);
    int cw=ccw(a,b,point(0,0));
    if(cw==LEFT&&0<=a.imag()&&b.imag()<0)++cnt;
    if(cw==OVER)return false;
  }
  if(cnt&1)return true;
  else return false;
}

struct State{
  int n;
  elem cost;
  State(int n, elem cost):n(n),cost(cost){}
  State(){}
  bool operator<(const State &t)const{
    return cost > t.cost;
  }
};

#define MAXN 512

int N;
point B[MAXN][128];
int nB[MAXN];
int nG;
point G[MAXN];
int GSafe[MAXN];
int nGoal;
point Goal[2*MAXN];
int conv[MAXN][MAXN];
bool Unconnected[MAXN][MAXN]; //when there is no segments between i and j where i and j is one of segments of buildings.

bool isConnected( const point &a, const point &b){
  point x=(a+b)/(elem)2.0;
  for(int i = 0; i < N; ++i){
    if(inSimple(x,nB[i],B[i]))return false;
    for(int j = 0; j < nB[i]; ++j){
      point p=B[i][j];
      point np=B[i][(1+j)%nB[i]];
      point tmp;
      if(intersectionSS(seg(a,b),seg(p,np),tmp)){
	if(far(tmp,a)&&far(tmp,b))return false;
      }
    }
  }
  return true;
}

elem solve(){
  elem ret = infty;
  elem A[nG];
  bool visited[nG];
  bool adj[nG][nG];
  priority_queue<State> Q;
  State init(0,0.0);
  Q.push(init);

  for(int i = 0; i < nG; ++i){
    visited[i] = false;
    A[i] = infty;
    for(int j = 0; j < nG; ++j){
      adj[i][j]=false;
    }
  }

  elem remain[nG];
  for(int i = 0; i < nG; ++i){
    elem rem = infty;
    for(int j = 0; j < nG; ++j){
      if( GSafe[j] ){
	rem = min(rem, abs(G[j]-G[i]));
      }
    }
    for(int j = 0; j < nGoal; ++j){
      rem = min( rem, abs(Goal[j]-G[i]) ); 
    }
    remain[i] = rem;
  }
  
  A[0] = 0.0;
  while(!Q.empty()){
    State nst = Q.top(); Q.pop();
    if(visited[nst.n])continue;
    visited[nst.n]=true;
    point np = G[nst.n];
    if(GSafe[nst.n]){
      ret=min(ret,nst.cost);
      break;
    }
    if( nst.cost + remain[nst.n] >= ret ) continue; 

    for(int i = 0; i < nGoal; ++i){
      if( isConnected(np,Goal[i]) ){
	ret = min(ret,nst.cost+abs(Goal[i]-np));
      }
    }

    for(int i = 1; i < nG; ++i){
      if( nst.n == i ) continue;
    retry:;
      if( adj[nst.n][i] ){
	elem nxcost = nst.cost + abs(G[i]-np);
	if( A[i] > nxcost ){
	  A[i]=nxcost;
	  if(!visited[i]){
	    Q.push(State(i,nxcost));
	  }
	}
      }else{
	if( isConnected(np,G[i]) ){
	  adj[nst.n][i]=adj[i][nst.n]=true;
	  goto retry;
	}
      }
    }
  }

  int min_i = -1;
  for(int i = 0; i < nG; ++i){
    if( GSafe[i] ){
      if( ret > A[i] ){
	ret = A[i];
	min_i = i;
      }
    }
  }
  return ret;
}

bool eqseg(seg a, seg b){
  return
    (near(a.fr,b.fr)&&near(a.sc,b.sc))||
    (near(a.fr,b.sc)&&near(a.sc,b.fr));
}

int main(){
  point p(0,0);
  point s;

  while(true){
    // input
    cin >> N;
    if(N==0)break;
    elem bx,by;
    cin >> bx >> by;
    point bomb(bx,by);
    point alice(0,0);

    for(int i = 0; i < N; ++i){
      int m;
      cin >> m;
      nB[i]=m;
      for(int j = 0; j < m; ++j){
	elem x,y;
	cin >> x >> y;
	B[i][j]=point(x,y);
      }
    }

    for(int i = 0; i < N; ++i){
      for(int j = 0; j < nB[i]; ++j){
	point p = B[i][j];
	point nexp = B[i][(j+1)%nB[i]];
      }
    }
    
    // graph points
    nG=1;
    nGoal=0;
    G[0]=alice;
    GSafe[0]=0;
    for(int i = 0; i < N; ++i){
      for(int j = 0; j < nB[i]; ++j){

	point p = B[i][j];
	// vertex
	G[nG]=p;
	conv[i][j]=nG;
	{
	  // is safe vertex ?
	  bool safe = false;
	  point prep = B[i][(j-1+nB[i])%nB[i]];
	  point nexp = B[i][(j+1)%nB[i]];
	  point cp = (p + prep) / (elem)2.0;
	  point cx = (p + nexp) / (elem)2.0;
	  hline lcp(bomb,cp);
	  hline lcx(bomb,cx);
	  
	  point tmp;
	  
	  // there is a segment that guards alice from bomb
	  if( intersectionSS(seg(bomb,alice),seg(p,prep),tmp)&&
	      far(tmp,bomb)&&far(tmp,alice)){
	    GSafe[0]=1;
	  }

	  for(int k = 0; k < N; ++k){
	    for(int m = 0; m < nB[k]; ++m){
	      seg s(B[k][m],B[k][(m+1)%nB[k]]);
	      if( eqseg(lcp,s) ) continue;
	      point is;
	      if( intersectionSS( lcp,s,is ) && far( is, cp ) && abs(is-bomb)<abs(cp-bomb) ){
		if( ccw(p,prep,alice)==OVER ){
		  GSafe[0]=1;
		}
		safe = true;
	      }
	      if( intersectionSS( lcx,s,is ) && far( is, cx ) && abs(is-bomb)<abs(cx-bomb) ){
		if( ccw(p,nexp,alice)==OVER ){
		  GSafe[0]=1;
		}
		safe = true;
	      }
	    }
	    if(safe)break;
	  }
	  if(safe){
	    GSafe[nG]=1;
	  }else{
	    GSafe[nG]=0;
	  }
	}
	++nG;
	
	
	// vertical line
	if(far(bomb,p)){
	  hline l(bomb,p);
	  line al(alice,alice+unmr(bomb-p));
	  point is;
	  if( intersectionLH(al,l,is)){
	    bool skip=false;
	    //vis << "line("<<alice.real()<<","<<alice.imag()<<","<<is.real()<<","<<is.imag()<<");"<<endl;
	    for(int k = 0; k < N; ++k){
	      if(inSimple(is,nB[k],B[k]))skip=true;
	      for(int m = 0; m < nB[k]; ++m){
		if( near(is,B[k][m])||near(is,alice) ){
		  skip=true;
		}
	      }
	    }
	    if(!skip&&abs(is-bomb)>abs(p-bomb)){
	      Goal[nGoal]=is;
	      nGoal++;
	    }
	  }
	  
	  // half line and polygon
	  for(int k = 0; k < N; ++k){
	    for(int m = 0; m < nB[k]; ++m){
	      seg s(B[k][m],B[k][(m+1)%nB[k]]);
	      if( intersectionHS( l,s,is ) ){
		if(far(is,p)&&far(is,s.first)&&far(is,s.second)&&abs(is-bomb)>abs(p-bomb)){
		  Goal[nGoal]=is;
		  nGoal++;
		}
	      }
	    }
	  }
	}
      }
    }

    printf("%.12lf\n", solve());
  }
  return 0;
}

Measured memory_bytes: 2536