/*
* Author: Paul - Dan Baltescu, University of Bucharest
*/
#include <fstream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <cmath>
using namespace std;
const int MAXM = 30;
const int MAXP = 550;
const int INF = 1000000000;
const double eps = 0.00000001;
#define getSemiplane(p) (p.x > 0 || (p.x == 0 && p.y > 0))
#define ff first
#define ss second
struct Point
{
double x, y;
Point() :x(0), y(0) {}
Point(double a, double b) : x(a), y(b) {}
Point operator-(Point p) const
{
return Point(x - p.x, y - p.y);
}
Point operator+(Point p) const
{
return Point(x + p.x, y + p.y);
}
int operator==(Point p) const
{
return x == p.x && y == p.y;
}
friend istream& operator>>(istream &fin, Point &p)
{
fin >> p.x >> p.y;
return fin;
}
friend ostream& operator<<(ostream &fout, Point p)
{
fout << "(" << p.x << "," << p.y << ")";
return fout;
}
};
int M, N;
double Sol;
vector <Point> robot, puncte;
vector <Point> obst[MAXM];
Point start, finish;
vector < pair <int, double> > A[MAXP];
int U[MAXP];
double Cost[MAXP];
void readData()
{
ifstream fin("robot.in");
int N;
fin >> N;
for (int i = 0; i < N; ++i)
{
Point p;
fin >> p;
robot.push_back(p);
}
fin >> M;
for (int i = 0; i < M; ++i)
{
int nr;
fin >> nr;
for (int j = 0; j < nr; ++j)
{
Point p;
fin >> p;
obst[i].push_back(p);
}
}
start = robot[0];
for (int i = 1; i < (int) robot.size(); ++i)
{
if (robot[i].x < start.x) start.x = robot[i].x;
if (robot[i].y < start.y) start.y = robot[i].y;
}
fin >> finish;
}
int cmp(Point p1, Point p2)
{
int sp1 = getSemiplane(p1);
int sp2 = getSemiplane(p2);
return sp1 < sp2 || (sp1 == sp2 && p1.y*p2.x < p1.x*p2.y);
}
inline double crossProduct(Point p1, Point p2, Point p3)
{
return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
}
vector <Point> buildObstacle(const vector <Point>& polig1, const vector <Point>& polig2)
{
vector <Point> vect, res;
// creez un set de vectori matematici astfel:
// laturile din robot parcurse in sens antitrigonometric
// laturile din obstacol parcurse in sens trigonometric
for (int i = 1; i < (int) polig1.size(); ++i) vect.push_back(polig1[i-1] - polig1[i]);
vect.push_back(polig1[ polig1.size()-1 ] - polig1[0]);
for (int i = 1; i < (int) polig2.size(); ++i) vect.push_back(polig2[i] - polig2[i-1]);
vect.push_back(polig2[0] - polig2[ polig2.size()-1 ]);
// sortez vectorii roata in jurul originii
sort(vect.begin(), vect.end(), cmp);
// stabilesc unde trebuie translatat obstacolul
Point p1 = polig1[0], p2 = polig1[0], p3 = polig2[0];
for (int i = 1; i < (int) polig1.size(); ++i)
{
if (polig1[i].y < p1.y) p1 = polig1[i];
if (polig1[i].x < p2.x || (polig1[i].x == p2.x && polig1[i].y < p2.y)) p2 = polig1[i];
}
for (int i = 1; i < (int) polig2.size(); ++i)
if (polig2[i].x > p3.x || (polig2[i].x == p3.x && polig2[i].y > p3.y)) p3 = polig2[i];
p3 = p3 - Point(0, p2.y - p1.y);
// construiesc noul obstacol
res.push_back(p3);
for (int i = 0; i < (int) vect.size() - 1; ++i) res.push_back(res[i] + vect[i]);
assert(res.size() == vect.size());
assert(res[res.size() - 1] + vect[ vect.size() - 1] == p3);
return res;
}
inline int crossed(Point p1, Point p2, Point p3, Point p4)
{
// intersectez bounding box-urile
if (max(min(p1.x, p2.x), min(p3.x, p4.x)) > min(max(p1.x, p2.x), max(p3.x, p4.x))) return 0;
if (max(min(p1.y, p2.y), min(p3.y, p4.y)) > min(max(p1.y, p2.y), max(p3.y, p4.y))) return 0;
// intersectez segmentele
int v1 = crossProduct(p1, p2, p3) * crossProduct(p1, p2, p4);
int v2 = crossProduct(p3, p4, p1) * crossProduct(p3, p4, p2);
return v1 < 0 && v2 < 0;
}
inline double dist(Point p1, Point p2)
{
return sqrt((p1.x-p2.x) * (p1.x-p2.x) + (p1.y-p2.y) * (p1.y-p2.y));
}
inline int goodSegment(Point p1, Point p2)
{
for (int i = 0; i < M; ++i)
for (int j = 1; j < (int) obst[i].size(); ++j)
for (int k = j+1; k < (int) obst[i].size(); ++k)
if (crossed(p1, p2, obst[i][j], obst[i][k])) return 0;
return 1;
}
void makeGraph()
{
// Aleg punctele interesante
puncte.push_back(start);
for (int i = 0; i < M; ++i)
for (int j = 0; j < (int) obst[i].size(); ++j) puncte.push_back(obst[i][j]);
puncte.push_back(finish);
N = puncte.size();
// Fac graful propriu-zis
for (int i = 0; i < N; ++i)
for (int j = i+1; j < N; ++j)
if (goodSegment(puncte[i], puncte[j]))
{
A[i].push_back( make_pair(j, dist(puncte[i], puncte[j])) );
A[j].push_back( make_pair(i, dist(puncte[i], puncte[j])) );
}
}
double doDijkstra()
{
for (int i = 1; i < N; ++i) Cost[i] = INF;
for (int i = 1; i < N && !U[N-1]; ++i)
{
int nod = 0;
for (int j = 1; j < N; ++j)
if (!U[j] && (Cost[j] < Cost[nod] || U[nod])) nod = j;
for (int j = 0; j < (int) A[nod].size(); ++j)
if (Cost[nod] + A[nod][j].ss < Cost[A[nod][j].ff]) Cost[A[nod][j].ff] = Cost[nod] + A[nod][j].ss;
U[nod] = 1;
}
if (Cost[N-1] == INF) return -1;
return Cost[N-1];
}
void writeData()
{
ofstream fout("robot.out");
fout.precision(2);
fout << fixed << Sol << endl;
}
int main()
{
readData();
for (int i = 0; i < M; ++i) obst[i] = buildObstacle(robot, obst[i]);
makeGraph();
Sol = doDijkstra();
writeData();
return 0;
}