Problem:
Problem J:
Blue Forest
John is playing a famous console game named 'Tales of Algorithmers.' Now he is facing the last dungeon called 'Blue Forest.' To find out the fastest path to run through the very complicated dungeon, he tried to draw up the dungeon map.
The dungeon consists of several floors. Each floor can be described as a connected simple plane graph. Vertices of the graph are identified by X-Y coordinate, and the length of an edge is calculated by Euclidean distance. A vertex may be equipped with a one-way warp gate. If John chooses to use the gate, it brings John to another vertex in a possibly different floor. The distance between a warp gate and its destination is considered as 0.
One vertex has at most one warp gate, though some vertices might be the destination of multiple warp gates.
He believed he made one map for each floor, however after drawing maps of all the floors, he
noticed that he might have made a few mistakes. He might have drawn the same floor several times, and might have forgotten to mark some warp gates in the maps. However, he was sure he marked all warp gates at least once. So if the maps of same floor are unified to one map, all the warp gates must be described there. Luckily there are no floors which have the same shape
as the other floors, so if two (or more) maps can be unified, they must be the maps of the same floor. Also, there is no floor which is circular symmetric (e.g. a regular triangle and a square).
Map A and map B can be unified if map B can be transformed to map A using only rotation and parallel translation. Since some of the warp gates on maps might be missing, you should not consider the existence of warp gates when checking unification. If it is possible to unify map A and map B, a vertex on map A and the corresponding vertex on map B are considered as 'identical' vertices. In other words, you should treat warp gates on map B as those on map A where the warp gates are located on the corresponding vertices on map A. Destinations of warp gates should be treated similarly. After that you can forget map B. It is guaranteed that if both map A and map B have warp gates which are on the identical vertices, the destinations of them are also identical.
Remember, your task is to find the shortest path from the entrance to the exit of the dungeon, using the unified maps.
Input
The input consists of multiple datasets. Each dataset is in the following format.
n
component
1
component
2
...
component
n
sl sn
dl dn
n
is a positive integer indicating the number of maps.
component
i
describes the
i
-th map in the following format.
A
x
1
y
1
x
2
y
2
...
x
A
y
A
B
s
1
d
1
s
2
d
2
...
s
B
d
B
C
sn
1
dl
1
dn
1
sn
2
dl
2
dn
2
...
sn
C
dl
C
dn
C
A
denotes the number of vertices in the map. Each of the following
A
lines contains two integers
x
i
and
y
i
representing the coordinates of the
i
-th vertex in the 2-dimensional plane.
B
denotes the number of the edges connecting the vertices in the map. Each of the following
...(truncated)

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
#define f first
#define s second
#define ff f,f
#define fs f.s
#define sf s.f
#define ss s.s
#define mp make_pair
#define MAX 51
#define inf 1e10
#define eps (1e-11)
#define pi M_PI
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;

typedef pair<double,double> Pd;
typedef pair<int,int> P;
typedef pair<Pd,Pd> PP;

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

  Point operator+(Point p){ return Point(x+p.x,y+p.y);}
  Point operator-(Point p){ return Point(x-p.x,y-p.y);}
  Point operator*(double k){ return Point(x*k,y*k);}
  Point operator/(double k){ return Point(x/k,y/k);}
  bool operator<(Point p)const{ return (x!=p.x ? x<p.x : y<p.y);}
  bool operator==(Point p)const{ return fabs(x-p.x)<eps && fabs(y-p.y)<eps;}

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

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

class edge{
  public:
    int l,n;
    double cost;
    edge(int l,int n,double cost):l(l),n(n),cost(cost){}
};

class State{
  public:
    int l,n;
    double cost;
    State(int l,int n,double cost):l(l),n(n),cost(cost){}
    bool operator<(State s)const{ return s.cost<cost; }
};

int n,sl,sn,dl,dn;
vector<Point> vp[MAX];
vector<P> vs[MAX];
vector<edge> e[MAX][MAX];

void init(){
  for(int i=0;i<MAX;i++){
    vp[i].clear();
    vs[i].clear();
    for(int j=0;j<MAX;j++)e[i][j].clear();
  }
}

double getAngle(Vector a,Vector b){
  double r=acos(dot(a,b)/(abs(a)*abs(b)))*180/pi;
  if(cross(a,b)<-eps)r=360-r;
  return r;
}

double dijkstra(){
  double d[MAX][MAX];
  for(int i=0;i<MAX;i++)for(int j=0;j<MAX;j++)d[i][j]=inf;
  priority_queue<State> pq;
  pq.push(State(sl,sn,0));
  d[sl][sn]=0;

  while(pq.size()){
    State u=pq.top();
    pq.pop();
    if(d[u.l][u.n]-u.cost<-eps)continue;

    for(int i=0;i<e[u.l][u.n].size();i++){
      edge E=e[u.l][u.n][i];
      if(u.cost+E.cost-d[E.l][E.n]<-eps){
        d[E.l][E.n]=u.cost+E.cost;
        pq.push(State(E.l,E.n,d[E.l][E.n]));
      }
    }
  }
  if(d[dl][dn]==inf)return -1;
  return d[dl][dn];
}

void check(int a,int b){
  if(vs[a].size()!=vs[b].size())return;
  if(vp[a].size()!=vp[b].size())return;
  P v=vs[a][0];
  map<int,int> ver;
  Point A=vp[a][v.f],B=vp[a][v.s];
  for(int i=0;i<vs[b].size();i++){
    P u=vs[b][i];
    Point C=vp[b][u.f],D=vp[b][u.s];
    if(!equals(abs(B-A),abs(D-C)))continue;
    map<PP,P> mp;
    for(int j=0;j<vs[b].size();j++){
      P w=vs[b][j];
      Point E=vp[b][w.f];
      Point F=vp[b][w.s];
      PP tmp=PP(Pd(abs(E-C),getAngle(D-C,E-C)),
                Pd(abs(F-C),getAngle(D-C,F-C)));
      mp[tmp]=w;
    }
    bool flag=true;
    for(int j=0;j<vs[a].size();j++){
      P w=vs[a][j];
      Point E=vp[a][w.f];
      Point F=vp[a][w.s];
      PP tmp=PP(Pd(abs(E-A),getAngle(B-A,E-A)),
                Pd(abs(F-A),getAngle(B-A,F-A)));
      if(mp.find(tmp)==mp.end()){
        flag=false;
        break;
      }
      ver[mp[tmp].f]=w.f;
      ver[mp[tmp].s]=w.s;
    }
    if(flag){
      for(int j=0;j<vp[b].size();j++){
        int k=ver[j];
        e[b][j].push_back(edge(a,k,0));
        e[a][k].push_back(edge(b,j,0));
      }
      return;
    }
  }
  return;
}

int main()
{
  while(1){
    cin>>n;
    if(n==0)break;
    init();
    for(int i=0;i<n;i++){
      int a,b,c,x,y,z,s,d;
      cin>>a;
      for(int j=0;j<a;j++){
        cin>>x>>y;
        vp[i].push_back(Point(x,y));
      }
      cin>>b;
      for(int j=0;j<b;j++){
        cin>>s>>d;
        s--;d--;
        vs[i].push_back(mp(s,d));
        vs[i].push_back(mp(d,s));
        e[i][s].push_back(edge(i,d,abs(vp[i][s]-vp[i][d])));
        e[i][d].push_back(edge(i,s,abs(vp[i][s]-vp[i][d])));
      }
      cin>>c;
      for(int j=0;j<c;j++){
        cin>>x>>y>>z;
        x--;y--;z--;
        e[i][x].push_back(edge(y,z,0));
      }
    }
    cin>>sl>>sn>>dl>>dn;
    sl--;sn--;dl--;dn--;
    
    for(int i=0;i<n;i++){
      for(int j=i+1;j<n;j++)check(i,j);
    }
    printf("%.10f\n",dijkstra());
  }
  return 0;
}
accuracy: 1
time_ms: 1230
memory_kb: 3612
final_rank: 5

code_snippet: #include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
int X[60][30];
int Y[60][30];
int g2[60][30][30];
int A[60];
int B[60];
int C[60];
double ijk[60][30];
int v[60][30];
int conv[30];
map<pair<int,int>,int> m[60];
double EPS=1e-9;
vector<pair<pair<int,int>,double> >g[60][30];
double dist(int a,int b,int c,int d){
	return sqrt((X[a][b]-X[c][d])*(X[a][b]-X[c][d])+(Y[a][b]-Y[c][d])*(Y[a][b]-Y[c][d]));
}
double ABS(double a){return max(a,-a);}
int UF[60];
int FIND(int a){
	if(UF[a]<0)return a;
	return UF[a]=FIND(UF[a]);
}
void UNION(int a,int b){
	a=FIND(a);b=FIND(b);if(a==b)return;
	UF[a]+=UF[b];UF[b]=a;
}
int main(){
	int a;
	while(scanf("%d",&a),a){
		for(int i=0;i<60;i++)for(int j=0;j<30;j++){
			g[i][j].clear();
			for(int k=0;k<30;k++)g2[i][j][k]=0;
		}
		for(int i=0;i<a;i++)UF[i]=-1;
		for(int i=0;i<a;i++){
			m[i].clear();
			int b;scanf("%d",&b);
			A[i]=b;
			for(int j=0;j<b;j++){
				scanf("%d%d",&X[i][j],&Y[i][j]);
				m[i][make_pair(X[i][j],Y[i][j])]=j;
			}
			int c;scanf("%d",&c);
			B[i]=c;
			for(int j=0;j<c;j++){
				int p,q;
				scanf("%d%d",&p,&q);p--;q--;
				g[i][p].push_back(make_pair(make_pair(i,q),dist(i,p,i,q)));
				g[i][q].push_back(make_pair(make_pair(i,p),dist(i,p,i,q)));
				g2[i][p][q]=g2[i][q][p]=1;
			}
			int d;scanf("%d",&d);
			C[i]=d;
			for(int j=0;j<d;j++){
				int p,q,r;
				scanf("%d%d%d",&p,&q,&r);p--;q--;r--;
				g[i][p].push_back(make_pair(make_pair(q,r),0));
			}
		}
		for(int i=0;i<a;i++){
			for(int j=i+1;j<a;j++){
				if(A[i]!=A[j]||B[i]!=B[j])continue;
				if(FIND(i)==FIND(j))continue;
				for(int k=0;k<A[j];k++){
					if(FIND(i)==FIND(j))break;
					for(int l=0;l<A[j];l++){
						if(ABS(dist(i,0,i,1)-dist(j,k,j,l))>EPS)continue;
						double th=atan2(Y[i][1]-Y[i][0],X[i][1]-X[i][0])-atan2(Y[j][l]-Y[j][k],X[j][l]-X[j][k]);
						bool ok=true;
						for(int x=0;x<A[j];x++){
							double vx=X[j][x]-X[j][k];
							double vy=Y[j][x]-Y[j][k];
							double tx=cos(th)*vx-sin(th)*vy;
							double ty=sin(th)*vx+cos(th)*vy;
							int sx=(int)(X[i][0]+tx+0.5);int sy=(int)(Y[i][0]+ty+0.5);
							if(X[i][0]+tx+0.5<0)sx--;
							if(Y[i][0]+ty+0.5<0)sy--;
							
							if(ABS(X[i][0]+tx-sx)>EPS||ABS(Y[i][0]+ty-sy)>EPS){ok=false;break;}
							if(m[i].count(make_pair(sx,sy))==0){ok=false;break;}
							conv[m[i][make_pair(sx,sy)]]=x;
						}
						if(!ok)continue;
						for(int x=0;x<A[i];x++){
							for(int y=0;y<g[i][x].size();y++){
								if(g[i][x][y].second<EPS)continue;
								if(!g2[j][conv[x]][conv[g[i][x][y].first.second]]){ok=false;break;}
							}
						}
						if(ok){
							UNION(i,j);
							for(int x=0;x<A[i];x++){
								g[i][x].push_back(make_pair(make_pair(j,conv[x]),0));
								g[j][conv[x]].push_back(make_pair(make_pair(i,x),0));
							}
							break;
						}
					}
				}
			}
		}
		priority_queue<pair<double,pair<int,int> > >Q;
		int s1,s2,d1,d2;
		scanf("%d%d%d%d",&s1,&s2,&d1,&d2);
		s1--;s2--;d1--;d2--;
		Q.push(make_pair(0,make_pair(s1,s2)));
		for(int i=0;i<60;i++)for(int j=0;j<30;j++){
			ijk[i][j]=999999999;
			v[i][j]=0;
		}
		ijk[s1][s2]=0;
		while(Q.size()){
			double cost=-Q.top().first;
			int at1=Q.top().second.first;
			int at2=Q.top().second.second;
		//	printf("%d %d %f\n",at1,at2,cost);
			Q.pop();
			if(v[at1][at2])continue;
			v[at1][at2]=1;
			for(int i=0;i<g[at1][at2].size();i++){
				int tr=g[at1][at2][i].first.first;
				int tc=g[at1][at2][i].first.second;
				double val=g[at1][at2][i].second;
				if(!v[tr][tc]&&ijk[tr][tc]>cost+val+EPS){
					ijk[tr][tc]=cost+val;
					Q.push(make_pair(-ijk[tr][tc],make_pair(tr,tc)));
				}
			}
		}
		if(ijk[d1][d2]>999999998)printf("-1\n");
		else printf("%f\n",ijk[d1][d2]);
	}
}
accuracy: 1
time_ms: 90
memory_kb: 1676
final_rank: 2

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>
typedef complex<double> Point;
struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};
namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    if (round(lhs.real()) == round(rhs.real()) &&
        round(lhs.imag()) == round(rhs.imag())) { return false; }
    if (round(lhs.real()) != round(rhs.real())) { return lhs.real() < rhs.real(); }
    return lhs.imag() < rhs.imag();
  }
  bool operator<(const Line &lhs, const Line &rhs) {
    if (lhs[0] < rhs[0] || rhs[0] < lhs[0]) { return lhs[0] < rhs[0]; }
    return lhs[1] < rhs[1];
  }
};

typedef double Weight;
struct Edge {
  int src;
  int dest;
  Weight weight;
  Edge(int src, int dest, Weight weight) : src(src), dest(dest), weight(weight) {;}
  bool operator<(const Edge &rhs) const {
    if (weight != rhs.weight) { return weight > rhs.weight; }
    if (src != rhs.src) { return src < rhs.src; }
    return dest < rhs.dest;
  }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void PrintMatrix(const Matrix &matrix) {
  for (int y = 0; y < (int)matrix.size(); y++) {
    for (int x = 0; x < (int)matrix[y].size(); x++) {
      printf("%f ", matrix[y][x]);
    }
    puts("");
  }
}

Weight Dijkstra(const Graph &g, int s, int t) {
  const int n = g.size();
  vector<bool> visit(n, false);
  Array dist(n, 2000000000LL);
  priority_queue<Edge> que;
  que.push(Edge(s, s, 0));
  Weight ans = -1;
  dist[s] = 0;
  while (!que.empty()) {
    Edge edge = que.top();
    que.pop();
    int from = edge.dest;
    if (visit[from]) { continue; }
    visit[from] = true;
    if (from == t) {
      ans = edge.weight;
      break;
    }   
    for (int i = 0; i < (int)g[from].size(); i++) {
      int to = g[from][i].dest;
      Weight ncost = edge.weight + g[from][i].weight;
      if (visit[to] || ncost - dist[to] >= -EPS) { continue; }
      dist[to] = ncost;
      que.push(Edge(from, to, ncost));
    }   
  }
  return ans;
}

//============================================

int n, m;
int mapto[60][30];
vector<Point> ps[60];
map<Point, int> pmapto[60];
vector<Line> ls1[60];
set<Line> ls2[60];
vector<int> fs[60];
vector<int> ts[60];

vector<int> wfl;
vector<int> wfn;
vector<int> wtl;
vector<int> wtn;

void Merge(Graph &g, int from, int to) {
  REP(i, ls1[to].size()) {
    Point c = ls1[to][i][0];
    Point vect = ls1[to][i][0] - ls1[from][0][0];
    //cout << from << " " << to << " " << i << " " << vect << endl;
    vector<Line> ls = ls1[from];
    FORIT(it, ls) {
      REP(iter, 2) {
        (*it)[iter] += vect;
        //cout << (*it)[iter] << endl;
      }
    }
    //cout << ls1[to][i][1] << " " << ls[0][1] << endl;
    double angle = arg(ls1[to][i][1] - c) - arg(ls[0][1] - c);
    Point rot = Point(cos(angle), sin(angle));
    FORIT(it, ls) {
      REP(iter, 2) {
        (*it)[iter] = ((*it)[iter] - c) * rot + c;
      }
      if (!ls2[to].count(*it)) { goto next; }
    }
    REP(j, ps[from].size()) {
      Point p = (ps[from][j] + vect - c) * rot + c;
      assert(pmapto[to].count(p));
      int f = mapto[from][j];
      int t = pmapto[to][p];
      //int t = mapto[to][nj];
      g[f].push_back(Edge(f, t, 0));
      g[t].push_back(Edge(t, f, 0));
    }
    return;
next:;
  }
}

int main() {
  while (scanf("%d", &n), n) {
    MEMSET(mapto, 0xdf);
    REP(i, 60) {
      ps[i].clear();
      pmapto[i].clear();
      ls1[i].clear();
      ls2[i].clear();
      fs[i].clear();
      ts[i].clear();
    }
    wfl.clear();
    wfn.clear();
    wtl.clear();
    wtn.clear();
    m = 0;
    REP(i, n) {
      int k;
      scanf("%d", &k);
      REP(j, k) {
        int x, y;
        scanf("%d %d", &x, &y);
        Point p = Point(x, y);
        ps[i].push_back(p);
        mapto[i][j] = m;
        pmapto[i][p] = m;
        m++;
      }
      scanf("%d", &k);
      REP(j, k) {
        int f, t;
        scanf("%d %d", &f, &t);
        f--; t--;
        fs[i].push_back(f);
        ts[i].push_back(t);
      }
      scanf("%d", &k);
      REP(j, k) {
        int f1 = i;
        int f2, t1, t2;
        scanf("%d %d %d", &f2, &t1, &t2);
        f2--; t1--; t2--;
        wfl.push_back(f1);
        wfn.push_back(f2);
        wtl.push_back(t1);
        wtn.push_back(t2);
      }
    }
    Graph g(m);
    REP(i, n) {
      REP(j, fs[i].size()) {
        int f = mapto[i][fs[i][j]];
        int t = mapto[i][ts[i][j]];
        double d = abs(ps[i][fs[i][j]] - ps[i][ts[i][j]]);
        g[f].push_back(Edge(f, t, d));
        g[t].push_back(Edge(t, f, d));
        Line l1 = Line(ps[i][fs[i][j]], ps[i][ts[i][j]]);
        Line l2 = Line(ps[i][ts[i][j]], ps[i][fs[i][j]]);
        ls1[i].push_back(l1);
        ls1[i].push_back(l2);
        ls2[i].insert(l1);
        ls2[i].insert(l2);
      }
    }
    REP(i, wfl.size()) {
      int f = mapto[wfl[i]][wfn[i]];
      int t = mapto[wtl[i]][wtn[i]];
      g[f].push_back(Edge(f, t, 0.0));
    }
    REP(i, n) {
      REP(j, i) {
        Merge(g, i, j);
      }
    }
    int sl, sn, dl, dn;
    scanf("%d %d %d %d", &sl, &sn, &dl, &dn);
    sl--; sn--; dl--; dn--;
    double ans = Dijkstra(g, mapto[sl][sn], mapto[dl][dn]);
    printf("%.8f\n", ans);
  }
}
accuracy: 1
time_ms: 7760
memory_kb: 0
final_rank: 4

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

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

using namespace std;

typedef pair<int,int> pii;

const double INF=1e77,EPS=1e-9;

struct Point{
	int x,y;
	Point operator-(const Point &p)const{ return (Point){x-p.x,y-p.y}; }
};

struct Edge{
	int j,v;
	double cost;
	bool warp;
};

struct Floor{
	int n;
	vector<Edge> adj[20];
};

int  dot (const Point &p,const Point &q){ return p.x*q.x+p.y*q.y; }
int cross(const Point &p,const Point &q){ return p.x*q.y-p.y*q.x; }

double norm2(const Point &p){ return dot(p,p); }

double dist(const Point &p,const Point &q){ return sqrt(norm2(p-q)); }

bool identify(int i,int j,const Floor *F,const Point P[50][20],int *sigma){
	if(F[i].n!=F[j].n) return false;

	int n=F[i].n;
	rep(a,n) rep(b,n) if(a!=b) {
		bool ok=true;
		rep(u,n){
			int v;
			for(v=0;v<n;v++){
				Point vec_i[2]={P[i][0]-P[i][u],P[i][1]-P[i][u]};
				Point vec_j[2]={P[j][a]-P[j][v],P[j][b]-P[j][v]};
				if(norm2(vec_i[0])==norm2(vec_j[0])
				&& norm2(vec_i[1])==norm2(vec_j[1])
				&&  dot (vec_i[0],vec_i[1])== dot (vec_j[0],vec_j[1])
				&& cross(vec_i[0],vec_i[1])==cross(vec_j[0],vec_j[1]))
					break;
			}
			if(v<n) sigma[u]=v;
			else    ok=false;
		}
		if(!ok) continue;

		bool adj_i[20][20]={},adj_j[20][20]={};
		rep(u,n) rep(k,F[i].adj[u].size()) {
			Edge e=F[i].adj[u][k];
			if(!e.warp) adj_i[u][e.v]=true;
		}
		rep(u,n) rep(k,F[j].adj[u].size()) {
			Edge e=F[j].adj[u][k];
			if(!e.warp) adj_j[u][e.v]=true;
		}

		rep(u,n) rep(v,n) if(adj_i[u][v]!=adj_j[sigma[u]][sigma[v]]) ok=false;
		if(!ok) continue;

		return true;
	}

	return false;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		Floor F[50];
		Point P[50][20];
		rep(i,n){
			scanf("%d",&F[i].n);
			rep(k,F[i].n) scanf("%d%d",&P[i][k].x,&P[i][k].y);
			int b; scanf("%d",&b);
			rep(k,b){
				int u,v; scanf("%d%d",&u,&v); u--; v--;
				F[i].adj[u].push_back((Edge){i,v,dist(P[i][u],P[i][v])});
				F[i].adj[v].push_back((Edge){i,u,dist(P[i][u],P[i][v])});
			}
			int c; scanf("%d",&c);
			rep(k,c){
				int u,j,v; scanf("%d%d%d",&u,&j,&v); u--; j--; v--;
				F[i].adj[u].push_back((Edge){j,v,0,true});
			}
		}
		int si,su,gi,gu; scanf("%d%d%d%d",&si,&su,&gi,&gu); si--; su--; gi--; gu--;

		rep(j,n) rep(i,j) {
			int sigma[20];
			if(identify(i,j,F,P,sigma)){
				rep(u,F[i].n){
					int v=sigma[u];
					F[i].adj[u].push_back((Edge){j,v,0,true});
					F[j].adj[v].push_back((Edge){i,u,0,true});
				}
			}
		}

		double d[50][20],ans=-1;
		rep(i,n) rep(u,20) d[i][u]=INF;
		d[si][su]=0;

		priority_queue< pair<double,pii> > pq;
		pq.push(make_pair(0,make_pair(si,su)));
		while(!pq.empty()){
			pair<double,pii> a=pq.top(); pq.pop();
			int i=a.second.first,u=a.second.second;
			if(d[i][u]+EPS<-a.first) continue;

			if(i==gi && u==gu){
				ans=d[gi][gu];
				break;
			}

			rep(k,F[i].adj[u].size()){
				Edge e=F[i].adj[u][k];
				double nextd=d[i][u]+e.cost;
				if(nextd+EPS<d[e.j][e.v]){
					d[e.j][e.v]=nextd;
					pq.push(make_pair(-nextd,make_pair(e.j,e.v)));
				}
			}
		}

		printf("%f\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 2950
memory_kb: 0
final_rank: 1

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

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

using namespace std;

typedef pair<int,int> pii;

const double INF=1e77,EPS=1e-9;

struct Point{
	int x,y;
	Point operator-(const Point &p)const{ return (Point){x-p.x,y-p.y}; }
};

struct Edge{
	int j,v;
	double cost;
	bool warp;
};

struct Floor{
	int n;
	vector<Edge> adj[20];
};

int  dot (const Point &p,const Point &q){ return p.x*q.x+p.y*q.y; }
int cross(const Point &p,const Point &q){ return p.x*q.y-p.y*q.x; }

double norm2(const Point &p){ return dot(p,p); }

double dist(const Point &p,const Point &q){ return sqrt(norm2(p-q)); }

bool identify(int i,int j,const Floor *F,const Point P[50][20],int *sigma){
	if(F[i].n!=F[j].n) return false;

	int n=F[i].n;
	rep(a,n) rep(b,n) if(a!=b) {
		bool ok=true;
		rep(u,n){
			int v;
			for(v=0;v<n;v++){
				Point vec_i[2]={P[i][0]-P[i][u],P[i][1]-P[i][u]};
				Point vec_j[2]={P[j][a]-P[j][v],P[j][b]-P[j][v]};
				if(norm2(vec_i[0])==norm2(vec_j[0])
				&& norm2(vec_i[1])==norm2(vec_j[1])
				&&  dot (vec_i[0],vec_i[1])== dot (vec_j[0],vec_j[1])
				&& cross(vec_i[0],vec_i[1])==cross(vec_j[0],vec_j[1]))
					break;
			}
			if(v<n) sigma[u]=v;
			else    ok=false;
		}
		if(!ok) continue;

		bool adj_i[20][20]={},adj_j[20][20]={};
		rep(u,n) rep(k,F[i].adj[u].size()) {
			Edge e=F[i].adj[u][k];
			if(!e.warp) adj_i[u][e.v]=true;
		}
		rep(u,n) rep(k,F[j].adj[u].size()) {
			Edge e=F[j].adj[u][k];
			if(!e.warp) adj_j[u][e.v]=true;
		}

		rep(u,n) rep(v,n) if(adj_i[u][v]!=adj_j[sigma[u]][sigma[v]]) ok=false;
		if(!ok) continue;

		return true;
	}

	return false;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		Floor F[50];
		Point P[50][20];
		rep(i,n){
			scanf("%d",&F[i].n);
			rep(k,F[i].n) scanf("%d%d",&P[i][k].x,&P[i][k].y);
			int b; scanf("%d",&b);
			rep(k,b){
				int u,v; scanf("%d%d",&u,&v); u--; v--;
				F[i].adj[u].push_back((Edge){i,v,dist(P[i][u],P[i][v])});
				F[i].adj[v].push_back((Edge){i,u,dist(P[i][u],P[i][v])});
			}
			int c; scanf("%d",&c);
			rep(k,c){
				int u,j,v; scanf("%d%d%d",&u,&j,&v); u--; j--; v--;
				F[i].adj[u].push_back((Edge){j,v,0,true});
			}
		}
		int si,su,gi,gu; scanf("%d%d%d%d",&si,&su,&gi,&gu); si--; su--; gi--; gu--;

		rep(j,n) rep(i,j) {
			int sigma[20];
			if(identify(i,j,F,P,sigma)){
				rep(u,F[i].n){
					int v=sigma[u];
					F[i].adj[u].push_back((Edge){j,v,0,true});
					F[j].adj[v].push_back((Edge){i,u,0,true});
				}
			}
		}

		double d[50][20],ans=-1;
		rep(i,n) rep(u,20) d[i][u]=INF;
		d[si][su]=0;

		priority_queue< pair<double,pii> > pq;
		pq.push(make_pair(0,make_pair(si,su)));
		while(!pq.empty()){
			pair<double,pii> a=pq.top(); pq.pop();
			int i=a.second.first,u=a.second.second;
			if(d[i][u]+EPS<-a.first) continue;

			if(i==gi && u==gu){ ans=d[gi][gu]; break; }

			rep(k,F[i].adj[u].size()){
				Edge e=F[i].adj[u][k];
				double nextd=d[i][u]+e.cost;
				if(nextd+EPS<d[e.j][e.v]){
					d[e.j][e.v]=nextd;
					pq.push(make_pair(-nextd,make_pair(e.j,e.v)));
				}
			}
		}

		printf("%f\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 2950
memory_kb: 984
final_rank: 3