Problem:
Problem B: Polygonal Line Search

Multiple polygonal lines are given on the xy-plane.
Given a list of polygonal lines and a template,
you must find out polygonal lines
which have the same shape as the template.

A polygonal line consists of several line segments parallel to x-axis or
y-axis. It is defined by a list of xy-coordinates of vertices from the start-point to the end-point in order,
and always turns 90 degrees at each vertex.
A single polygonal line does not pass the same point twice.

Two polygonal lines have the same shape when they
fully overlap each other only with rotation and translation
within xy-plane (i.e. without magnification or a flip).
The vertices given in reverse order from the start-point to the end-point is the
same as that given in order.

Figure 1 shows examples of polygonal lines.
In this figure, polygonal lines A and B have the same shape.

Write a program that answers polygonal lines which have the same shape as
the template.

Figure 1: Polygonal lines

Input

The input consists of multiple datasets.
The end of the input is indicated by a line which contains a zero.

A dataset is given as follows.

n

Polygonal line0

Polygonal line1

Polygonal line2

...

Polygonal linen

n is the number of polygonal lines for the object of search on
xy-plane.
n is an integer, and 1 <= n <= 50.
Polygonal line0 indicates the template.

A polygonal line is given as follows.

m

x1 y1

x2 y2

...

xm ym

m is the number of the vertices of a polygonal line (3 <= m <= 10).

xi and yi, separated by a space,
are the x- and y-coordinates
of a vertex, respectively (-10000 < xi < 10000, -10000 <yi < 10000).

Output

For each dataset in the input, your program should report numbers assigned to the polygonal lines that have the same shape as the template, in ascending order.
Each number must be written in a separate line without any other characters such as leading or trailing spaces.

Five continuous "+"s must be placed in a line at the end of each dataset.

Sample Input

5
5
0 0
2 0
2 1
4 1
4 0
5
0 0
0 2
-1 2
-1 4
0 4
5
0 0
0 1
-2 1
-2 2
0 2
5
0 0
0 -1
2 -1
2 0
4 0
5
0 0
2 0
2 -1
4 -1
4 0
5
0 0
2 0
2 1
4 1
4 0
4
4
-60 -75
-60 -78
-42 -78
-42 -6
4
10 3
10 7
-4 7
-4 40
4
-74 66
-74 63
-92 63
-92 135
4
-12 22
-12 25
-30 25
-30 -47
4
12 -22
12 -25
30 -25
30 47
3
5
-8 5
-8 2
0 2
0 4
8 4
5
-3 -1
0 -1
0 7
-2 7
-2 16
5
-1 6
-1 3
7 3
7 5
16 5
5
0 1
0 -2
8 -2
8 0
17 0
0

Output for the Sample Input

1
3
5
+++++
3
4
+++++
+++++

Solution in JAVA (judge verdict: Wrong Answer)

import java.util.*;
import static java.lang.Math.*;
public class Main {
	final Scanner sc = new Scanner(System.in);
	public static void main(String[] args) {
		new Main().run();
	}
	void run(){
		new AOJ1136();
	}
	
	class AOJ1136{
		AOJ1136(){
			while(true){
				int n=sc.nextInt();
				if(n==0)	break;
				solve(n);
				System.out.println("+++++");
			}
		}
		final int offset=10000,max=20010;
		void solve(int n){
			int m=sc.nextInt();
			ArrayList<HashSet<pair>> a=new ArrayList<HashSet<pair>>();
			for(int i=0; i<4; ++i)	a.add(new HashSet<pair>());
			HashSet<pair> tmp=new HashSet<pair>();
			int xmin=max, xmax=0, ymin=max, ymax=0;
			for(int i=0; i<m; ++i){
				int x=sc.nextInt(), y=sc.nextInt();
				x+=offset;
				y+=offset;
				tmp.add(new pair(x,y));
				xmin=min(xmin,x);
				xmax=max(xmax,x);
				ymin=min(ymin,y);
				ymax=max(ymax,y);
			}
			xmax-=xmin;
			ymax-=ymin;
			for(pair p: tmp)	a.get(0).add(new pair(p.x-xmin, p.y-ymin));
			for(int i=1; i<4; ++i)for(pair j: a.get(i-1))	a.get(i).add(new pair(j.y, (i%2==1?xmax:ymax)-j.x));
			
//			for(HashSet<pair> i:a)System.out.println(i);
			
			for(int i=1; i<=n; ++i){
				HashSet<pair> tmp2=new HashSet<pair>();
				xmin=max; xmax=0; ymin=max; ymax=0;
				int mm=sc.nextInt();
				for(int j=0; j<mm; ++j){
					int x=sc.nextInt(),y=sc.nextInt();
					x+=offset;
					y+=offset;
					tmp2.add(new pair(x,y));
					xmin=min(xmin,x);
					xmax=max(xmax,x);
					ymin=min(ymin,y);
					ymax=max(ymax,y);
				}
				if(mm!=m)	continue;
				HashSet<pair> tmp3=new HashSet<pair>();
				for(pair p: tmp2)	tmp3.add(new pair(p.x-xmin, p.y-ymin));
				for(HashSet<pair> h: a)if(tmp3.containsAll(h)){
					System.out.println(i);
					break;
				}
//				System.out.println(i+" "+tmp3);
			}
		}
		class pair{
			int x,y;
			pair(int x,int y){
				this.x=x;
				this.y=y;
			}
			pair rotate(){
				return new pair(this.y, max-this.x-1);
			}
			@Override public String toString(){
				return x+","+y;
			}
			@Override public int hashCode(){
				int ret=17;
				ret=ret*31+x;
				ret=ret*31+y;
				return ret;
			}
			@Override public boolean equals(Object o){
				if(this==o)	return true;
				if(!(o instanceof pair))	return false;
				pair p = (pair)o;
				return p.x==this.x&&p.y==this.y;
			}
		}
	}
	
	class AOJ1137{
		HashMap<Character,Integer> dic;
		AOJ1137(){
			int n=sc.nextInt();
			dic=new HashMap<Character,Integer>();
			dic.put('m', 1000);
			dic.put('c', 100);
			dic.put('x', 10);
			dic.put('i', 1);
			while(--n>=0)solve();
		}
		void solve(){
			String s1=sc.next(), s2=sc.next();
			int a1=toInt(s1),a2=toInt(s2);
			System.out.println(toMcxi(a1+a2));
		}
		int toInt(String s){
			char[] c=s.toCharArray();
			int ret=0,tmp=1;
			for(int i=0; i<c.length; ++i){
				if(Character.isDigit(c[i]))tmp=c[i]-'0';
				else{
					ret+=tmp*dic.get(c[i]);
					tmp=1;
				}
			}
			return ret;
		}
		String toMcxi(int a){
			StringBuilder ret=new StringBuilder();
			if(a/1000>0)	ret.append( (a/1000>1? (a/1000) : "") +"m");
			a=a%1000;
			if(a/100>0)		ret.append( (a/100>1? (a/100) : "") +"c");
			a=a%100;
			if(a/10>0)		ret.append( (a/10>1? (a/10) :"") +"x");
			a=a%10;
			if(a>0)			ret.append( (a>1? a : "") +"i");
			return ret.toString();
		}
	}
	
	class AOJ1140{
		int w,h;
		final int INF=Integer.MAX_VALUE/4;
		AOJ1140(){
			while(true){
				w=sc.nextInt();
				h=sc.nextInt();
				if((w|h)==0)	break;
				solve();
			}
		}
		void solve(){
			int[][] map=new int[w][h];
			int sx=0,sy=0,c=1;
			for(int y=0; y<h; ++y){
				char[] line=sc.next().toCharArray();
				for(int x=0; x<w; ++x){
					if(line[x]=='o'){
						sx=x;
						sy=y;
					}else if(line[x]=='x'){
						map[x][y]=-1;
					}else if(line[x]=='*'){
						map[x][y]=c++;
					}
				}
			}
			
			--c;	// number of dirty tile
			int b=(1<<c)-1;
//			System.out.println(Integer.bitCount(b));
//			System.out.println(Integer.toBinaryString(b));
			int[] vx={0,1,0,-1}, vy={-1,0,1,0};
			
			int[][][] closed=new int[w][h][b+1];
//			for(int x=0; x<w; ++x)for(int y=0; y<h; ++y)for(int z=0; z<=b; ++z)closed[x][y][z]=(x==sx&&y==sy?0:INF);
			for(int x=0; x<w; ++x)for(int y=0; y<h; ++y)for(int z=0; z<=b; ++z)closed[x][y][z]=INF;
			closed[sx][sy][b]=0;

			LinkedList<state> open=new LinkedList<state>();
			open.add(new state(sx,sy,b,0));
			
			int ans=-1;
			while(!open.isEmpty()){
				state now=open.poll();
//				System.out.println(now);
				if(now.t==0){
					ans=now.z;
					break;
				}
				for(int v=0; v<4; ++v){
					int xx=now.x+vx[v], yy=now.y+vy[v];
					if(!(0<=xx && xx<w && 0<=yy && yy<h))	continue;
					if(map[xx][yy]<0)	continue;
					
					int nt=now.t;
//					if(map[xx][yy]>0)	nt = now.t^(1<<(map[xx][yy]-1));
					if(map[xx][yy]>0 && (now.t&(1<<(map[xx][yy]-1)))>0 )	nt = now.t^(1<<(map[xx][yy]-1));
					
					if(closed[xx][yy][nt]<=now.z+1)	continue;
					closed[xx][yy][nt]=now.z+1;
					open.add(new state(xx,yy,nt,now.z+1));
				}
			}
			System.out.println(ans);
		}
		class state{
			int x,y,t,z;
			state(int x,int y,int t,int z){
				this.x=x;
				this.y=y;
				this.t=t;
				this.z=z;
			}
			@Override public String toString(){
				return "x:"+x+" y:"+y+" t:"+Integer.toBinaryString(t)+" z:"+z;
			}
		}
	}
	
	class AOJ1138{
		int n,m,p,a,b;
		final int INF=Integer.MAX_VALUE/4;
		AOJ1138(){
			while(true){
				n=sc.nextInt();
				m=sc.nextInt();
				p=sc.nextInt();
				a=sc.nextInt();
				b=sc.nextInt();
				if(n==0)	break;
				solve();
			}
		}
		void solve(){
			int[] tickets=new int[n];
			for(int i=0; i<n; ++i)	tickets[i]=sc.nextInt();
			int[][] path=new int[m][m];
			for(int i=0; i<m; ++i)for(int j=0; j<m; ++j)path[i][j]=INF;
			for(int i=0; i<p; ++i){
				int x=sc.nextInt(),y=sc.nextInt(),z=sc.nextInt();
				--x;
				--y;
				path[x][y]=z;
				path[y][x]=z;
			}
			
			--a;
			--b;
			
			int bit=(1<<n)-1;
//			System.out.println(Integer.bitCount(bit));
			double[][] closed=new double[m][bit+1];
			for(int i=0; i<m; ++i)for(int j=0; j<=bit; ++j)closed[i][j]=(i==a? 0 : INF);
			
			PriorityQueue<state> open = new PriorityQueue<state>();
			open.add(new state(a,bit,0));
			
			double ans=INF;
			
			while(!open.isEmpty()){
				state now = open.poll();
//				System.out.println(now);
				if(now.p==b){
					ans=min(ans,now.z);
					continue;
				}
				for(int to=0; to<m; to++){
					if(path[now.p][to]>=INF)	continue;
					if(now.p==to)	continue;
					for(int i=0; i<n; ++i){
						if( (now.t & (1<<i) ) == 0 )	continue;
						double a = (double)path[now.p][to]/(double)tickets[i];
						int b = now.t^(1<<i);
						if(closed[to][b] <= now.z+a)	continue;
						closed[to][b] = now.z+a;
						open.add(new state(to,b,now.z+a));
					}
				}
			}
			
			System.out.println(ans>=INF ? "Impossible" : ans);
		}
		class state implements Comparable<state>{
			int p,t;
			double z;
			state(int p,int t,double z){
				this.p=p;
				this.t=t;
				this.z=z;
			}
			@Override public int compareTo(state o){
				return (int)(this.z-o.z);
			}
			@Override public String toString(){
				return "p:"+p+" t:"+Integer.toBinaryString(t)+" z:"+z;
			}
		}
	}
	
	class AOJ1135{
		AOJ1135(){
			int n=sc.nextInt();
			while(--n>=0)	solve();
		}
		void solve(){
			int m=sc.nextInt(),y=sc.nextInt(),n=sc.nextInt(),ans=0;
			while(--n>=0){
				int a=sc.nextInt();
				double rate = sc.nextDouble();
				int b=sc.nextInt();
				if(a==0){
					int mm=m,c=0;
					for(int i=0; i<y; ++i){
						c += (double)mm*rate;
						mm-=b;
					}
					ans=max(ans, mm+c);
				}else{
					int mm=m;
					for(int i=0; i<y; ++i){
						mm+=(double)mm*rate;
						mm-=b;
					}
					ans=max(ans, mm);
				}
			}
			System.out.println(ans);
		}
	}
	
	

}