Problem:
NINJA GAME
新作ゲーム "NIN
JA G
AME" がついに発売となった．このゲームではプレイヤーは二次元マップ上の忍者を操作して移動を行う．二次元マップは
x
軸，または
y
軸のどちらか一方に平行な辺のみからなる，自己交差のない多角形で表される．いま，多角形の内部に存在するスタート地点からゴール地点へと移動する必要がある．
移動は上下左右と斜め45°の8方向が可能で，いずれかの対応するコマンドを入力すると，指定した方向に自動で進み続ける．この自動移動の最中の任意のタイミングで別のコマンドを入力した場合，即座に移動方向の転換が可能である．あなたの目標は，このゲームでの実績を解除するため，最小のコマンド入力回数でスタート地点からゴール地点に移動することである．
ここで気を付ける必要があるのは，キャラが忍者であるので，壁伝いの移動が可能であるということだ．ここで壁伝いの移動するとは，多角形の辺上を移動することである．ただし，もちろん多角形の外部に出ることはできない．壁伝いの移動中にその壁に対し垂直方向に移動しようとする場合はそれ以上移動できずに止まるのだが，一方で壁伝いの移動中に斜め方向に移動しようとする場合，壁と平行な方向への壁伝いの自動移動が続き，壁がなくなったところで元の斜め方向にまた自動移動を続ける．例えば下図のように
y
軸に平行な壁に
x
軸正方向と
y
軸負方向からなる斜め方向からぶつかった場合，ぶつかった後は壁に沿って
y
軸負方向に進み，壁がなくなったところでまた
x
軸正方向と
y
軸負方向からなる斜め方向へと進み始める．
ここで，斜め方向に移動しながら角にぶつかったときの挙動は以下のようになる．(a) のように両方向に壁が囲まれている場合はそこで止まり，方向転換をしなければ動けない．(b) や (c) のように角を通り過ぎてそのまま進める場合は，斜め方向に自動移動を続ける．(d) のように両方向に進める場合，好きな方向を選んで進めるものとしてよい．図では移動を表す矢印で壁が隠れるため少し内部側に寄せて図示しているが，これも実際には辺上を移動することを表す図である．
また，上下左右方向の移動中に角にぶつかったときの挙動は以下のようになる．(e), (f), (g) のような場合はそのままの方向に自動移動を続ける．(h) のように壁に垂直にぶつかった場合はそこで止まり，方向転換をしなければ動けない．ただし，同様に移動を表す矢印を壁から少し内部側に寄せているが，実際には辺上を移動することを表す図である．
上記の移動に関する挙動に従った上で，スタート地点からゴール地点に到達するために入力する必要があるコマンドの数の最小値を求めるプログラムを作成してほしい．例えば下図における最小のコマンド入力回数は，図中に示すように2である．これは3つ目のサンプル入力に対応している．
Input
入力は複数のデータセットからなる．
データセットの数は最大で 100 である．
各データセットは，次の形式で表される．
N
sx
sy
gx
gy
x
1
y
1
...
x
N
y
N
データセットの 1 行目はマップを表す多角形の頂点数を表す1つの整数
N
(
4 ≤ N ≤ 100
) からなる．2行目は4つの整数
sx
,
sy
,
gx
,
gy
(
-10,000 ≤ sx, sy, gx, gy ≤ 10,000
) からなり，スタート地点の座標が
(sx, sy)
，ゴール地点の座標が
(gx, gy)
であることを表している．続く
N
行では多角形の各頂点が反時計回り順に与えられる．このうち
i
行目は2つの整数
x
i
,
y
i
(
-10,000 ≤ x
i
, y
i
≤ 10,000
) からなり，
i
番目の頂点の座標が
(x
i
, y
i
)
であることを表す．ここで，与えられるスタート地点，ゴール地点，多角形は以下の制約を満たす．
全ての辺は
x
軸か
y
軸のいずれか一方に対して平行である．
与えられる多角形は自己交差を持たない．すなわち，各辺は端点以外で他の辺と交差せず，異なる
i, j
について
(x
i
, y
i
) ≠ (x
j
, y
j
)
である．
(sx, sy)
と
(gx, gy)
はともにこの多角形の内部 (辺上を含まない) にあることが保証される．
スタートとゴールは異なる，すなわち
(sx, sy) ≠ (gx, gy)
であることが保証される．
入力の終わりは 1 つのゼロからなる行で表される．
Output
各データセットに対し，スタート地点からゴール地点に辿り着くために必要な最小のコマンド入力の回数を 1 行で出力せよ．
Sample Input
8
1 1 2 2
0 2
0 0
2 0
2 1
3 1
3 3
1 3
1 2
12
-9 5 9 -9
0 0
0 -13
3 -13
3 -10
10 -10
10 10
-1 10
-1 13
-4 13
-4 10
-10 10
-10 0
12
3 57 53 2
0 0
64 0
64 18
47 18
47 39
64 39
64 60
0 60
0 44
33 44
33 30
0 30
0
Output for the Sample Input
1
1
2
1つ目の入力は下図 (1)，2つ目の入力は下図 (2) に対応する．

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001




#define SIZE 3005
const double NUM = 100000;
const double SMALL = 0.01;

enum DIR{
	to_U,
	to_R,
	to_D,
	to_L,
	to_RU,
	to_RD,
	to_LD,
	to_LU,
	None,
};
DIR dir_array[8] = {to_U,to_R,to_D,to_L,to_RU,to_RD,to_LD,to_LU};
DIR rev_dir[8] ={to_D,to_L,to_U,to_R,to_LD,to_LU,to_RU,to_RD};

enum Type{
	Tate,
	Yoko,
	R_UP, //右上がり
	L_UP, //左上がり
};

struct State{
	State(){
		node = sum_dist = 0;
		have_power = false;
		dir = None;	}

	State(int arg_node,int arg_sum_dist,bool arg_have_power,DIR arg_dir){
		node = arg_node;
		sum_dist = arg_sum_dist;
		have_power = arg_have_power;
		dir = arg_dir;
	}
	bool operator<(const struct State &arg) const{

		return sum_dist > arg.sum_dist; //昇順(PQ)
	}
	int node,sum_dist;
	bool have_power;
	DIR dir;
};

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{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return 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 Info{
	Info(int arg_p_index,int arg_e_index,double arg_value){
		p_index = arg_p_index;
		e_index = arg_e_index;
		value = arg_value;
	}
	bool operator<(const struct Info& arg) const{

		return value < arg.value;
	}
	int p_index,e_index;
	double value;
};

struct Edge{
	Edge(int arg_to,DIR arg_dir){
		to = arg_to;
		dir = arg_dir;
	}
	int to;
	DIR dir;
};


int N;
int num_point,num_line;
int min_dist[SIZE][10];
int PRE[SIZE];
Point point[SIZE];
Line line[SIZE];
vector<Info> V[SIZE];
map<int,bool> MAP[SIZE]; //MAP[辺番号][点番号] = その点を追加したか
int G[SIZE][9]; //G[点][方向] = 隣接ノード
bool ON_WALL[SIZE][9]; //壁上か
Type type[SIZE]; //線分のタイプ
double dx[8] = {0,1.0,0,-1.0,1.0,1.0,-1.0,-1.0},dy[8] = {1.0,0,-1.0,0,1.0,-1.0,-1.0,1.0};
DIR pre_dir[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;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
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);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


//交点を求める関数
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]);
}

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

int getIndex(Point tmp_p){

	for(int i = 0; i < num_point; i++){
		if(point[i] == tmp_p){

			return i;
		}
	}

	point[num_point] = tmp_p;

	int ret = num_point;
	num_point++;

	return ret;
}

bool is_exist(Line tmp_line){

	for(int i = 0; i < num_line; i++){
		if(line[i].p[0] == tmp_line.p[0]&&line[i].p[1]==tmp_line.p[1])return true;
		if(line[i].p[1] == tmp_line.p[0]&&line[i].p[0]==tmp_line.p[1])return true;

	}
	return false;
}


void register_Point(Point tmp_p,int line_index){

	int ind = getIndex(tmp_p);
	auto at = MAP[line_index].find(ind);

	if(at != MAP[line_index].end())return;

	MAP[line_index][ind] = true;

	double value;
	if(type[line_index] == Tate){

		value = tmp_p.y;
	}else{

		value = tmp_p.x;
	}

	V[line_index].push_back(Info(ind,line_index,value));
}

//fromから見てtoが方向dirの際に、辺を張る
void add_edge(int from,int to,DIR dir,int l_index){

	G[from][dir] = to;
	G[to][rev_dir[dir]] = from;

	if(l_index < N){

		ON_WALL[from][dir] = true;
		ON_WALL[to][rev_dir[dir]] = true;

	}else{

		ON_WALL[from][dir] = false;
		ON_WALL[to][rev_dir[dir]] = false;
	}
}


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

void func(){

	num_point = 0;
	num_line = 0;

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

		V[i].clear();
		MAP[i].clear();

		for(int a = 0; a < 8; a++){

			G[i][a] = -1;
			ON_WALL[i][a] = false;
		}
	}

	Point p_start,p_goal;

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

	int start = getIndex(p_start);
	int goal = getIndex(p_goal);

	Polygon poly;

	double x,y;

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

		scanf("%lf %lf",&x,&y);
		poly.push_back(Point(x,y));
	}

	Line st_line = Line(p_start,p_goal);

	double tmp_slope = calc_slope(st_line);

	if(fabs(tmp_slope-DBL_MAX) < EPS || fabs(tmp_slope) < EPS || fabs(tmp_slope-1.0) < EPS || fabs(tmp_slope+1.0) < EPS){

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

			Line work_line = Line(poly[i],poly[(i+1)%N]);
			if(is_Cross(st_line,work_line)){

				isOK = false;
				break;
			}
		}
		if(isOK){

			printf("1\n"); //スタートからゴールに直接行ける
			return;
		}
	}

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

		line[i].p[0] = poly[i];
		line[i].p[1] = poly[(i+1)%N];

		if(fabs(line[i].p[0].x-line[i].p[1].x) < EPS){

			type[i] = Tate;
		}else{

			type[i] = Yoko;
		}

		//点を辺に登録
		for(int k = 0; k < 2; k++){

			register_Point(line[i].p[k],i);
		}
	}

	//各点から8方向に移動させた直線を見る
	int num_line = N;

	int p_last = num_point;
	int l_last = N;

	vector<Point> P;

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

		Line base_line;
		base_line.p[0] = point[i];

		for(int k = 0; k < 8; k++){

			Vector tmp_vec = Vector(dx[k],dy[k]);
			Point tmp_p = base_line.p[0]+tmp_vec*SMALL;

			//微小移動した点がどこかの線分上にある、または外部ならSKIP
			if(contains(poly,tmp_p) != 2)continue;

			base_line.p[1] = base_line.p[0]+tmp_vec*NUM;

			double mini = HUGE_NUM;
			int l_index = -1;
			Point CROSS_P;

			for(int a = 0; a < l_last; a++){
				if(!is_Cross(base_line,line[a]))continue;

				Point cross_p = calc_Cross_Point(base_line,line[a]);
				if(cross_p == base_line.p[0] || cross_p == base_line.p[1])continue; //■端点を共有■

				double tmp_dist = calc_dist(base_line.p[0],cross_p);
				if(tmp_dist+EPS < mini){

					mini = tmp_dist;
					l_index = a;

					CROSS_P = cross_p;
				}
			}

			if(l_index == -1)continue;

			base_line.p[1] = CROSS_P;
			if(is_exist(base_line))continue; //既に見た辺

			//■まだ辺を張らない■

			if(k == 0 || k == 2){

				type[num_line] = Tate;

			}else if(k == 1 || k == 3){

				type[num_line] = Yoko;

			}else if(k == 4 || k == 6){

				type[num_line] = R_UP;

			}else{ //k == 5 || k == 7

				type[num_line] = L_UP;
			}

			line[num_line] = Line(base_line.p[0],base_line.p[1]);


			//点の登録
			register_Point(base_line.p[0],num_line); //■■■注意■■■
			register_Point(CROSS_P,num_line);
			register_Point(CROSS_P,l_index);

			if(type[num_line] == Tate || type[num_line] == Yoko){

				P.push_back(CROSS_P);
			}

			num_line++;
		}
	}

	//■縦横線で追加した点からの斜め線
	for(int i = 0; i < P.size(); i++){

		Line base_line;
		base_line.p[0] = P[i];

		for(int k = 4; k < 8; k++){

			Vector tmp_vec = Vector(dx[k],dy[k]);
			Point tmp_p = base_line.p[0]+tmp_vec*SMALL;

			//微小移動した点がどこかの線分上にある、または外部ならSKIP
			if(contains(poly,tmp_p) != 2)continue;

			base_line.p[1] = base_line.p[0]+tmp_vec*NUM;

			double mini = HUGE_NUM;
			int l_index = -1;
			Point CROSS_P;

			for(int a = 0; a < l_last; a++){
				if(!is_Cross(base_line,line[a]))continue;

				Point cross_p = calc_Cross_Point(base_line,line[a]);
				if(cross_p == base_line.p[0] || cross_p == base_line.p[1])continue; //■端点を共有■

				double tmp_dist = calc_dist(base_line.p[0],cross_p);
				if(tmp_dist+EPS < mini){

					mini = tmp_dist;
					l_index = a;

					CROSS_P = cross_p;
				}
			}

			if(l_index == -1)continue;

			base_line.p[1] = CROSS_P;
			if(is_exist(base_line))continue; //既に見た辺

			//■まだ辺を張らない■

			if(k == 0 || k == 2){

				type[num_line] = Tate;

			}else if(k == 1 || k == 3){

				type[num_line] = Yoko;

			}else if(k == 4 || k == 6){

				type[num_line] = R_UP;

			}else{ //k == 5 || k == 7

				type[num_line] = L_UP;
			}

			line[num_line] = Line(base_line.p[0],base_line.p[1]);

			//点の登録
			register_Point(base_line.p[0],num_line); //■■■注意■■■
			register_Point(CROSS_P,num_line);
			register_Point(CROSS_P,l_index);

			num_line++;
		}
	}

	//■辺同士の交点を見る■
	for(int i = 0; i < num_line-1; i++){
		for(int k = i+1; k < num_line; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			//if(cross_p == line[i].p[0] || cross_p == line[i].p[1])continue; //■端点を共有■

			register_Point(cross_p,i);
			register_Point(cross_p,k);
		}
	}

	//■同一辺上の点同士に辺を張る(全ての点は何かしらの辺上にあるはず)■
	for(int i = 0; i < num_line; i++){
		sort(V[i].begin(),V[i].end());

		for(int k = 0; k < V[i].size()-1; k++){

			int from = V[i][k].p_index;
			int to = V[i][k+1].p_index;

			if(type[i] == Tate){

				if(point[from].y < point[to].y){

					add_edge(from,to,to_U,i);

				}else{

					add_edge(from,to,to_D,i);
				}

			}else if(type[i] == Yoko){

				if(point[from].x < point[to].x){

					add_edge(from,to,to_R,i);
				}else{

					add_edge(from,to,to_L,i);
				}

			}else if(type[i] == R_UP){

				if(point[from].x < point[to].x){

					add_edge(from,to,to_RU,i);

				}else{

					add_edge(from,to,to_LD,i);
				}

			}else{ //L_UP

				if(point[from].x < point[to].x){

					add_edge(from,to,to_RD,i);

				}else{

					add_edge(from,to,to_LU,i);
				}
			}
		}
	}

	for(int i = 0; i < num_point; i++){
		for(int k = 0; k < 9; k++){

			min_dist[i][k] = BIG_NUM;
		}
	}

	priority_queue<State> Q;

	min_dist[start][None] = 0;

	Q.push(State(start,0,false,None));

	while(!Q.empty()){

		State state = Q.top();
		Q.pop();

		if(state.sum_dist > min_dist[state.node][state.dir])continue;

		if(state.node == goal){

			printf("%d\n",state.sum_dist);
			return;
		}

		//停止
		{
			if(min_dist[state.node][None] > state.sum_dist){

				min_dist[state.node][None] = state.sum_dist;
				Q.push(State(state.node,state.sum_dist,false,None));
			}
		}

		//コスト1を掛けて方向転換
		for(int i = 0; i < 8; i++){
			if(G[state.node][i] == -1)continue;

			int next_node = G[state.node][i];
			int next_dist = state.sum_dist+1;
			DIR next_dir = dir_array[i];

			if(min_dist[next_node][next_dir] > next_dist){

				min_dist[next_node][next_dir] = next_dist;
				Q.push(State(next_node,next_dist,true,next_dir));
			}
		}

		if(state.have_power){ //継続移動中

			if(G[state.node][state.dir] != -1){ //元々の方向にいけるなら進む

				int next_node = G[state.node][state.dir];
				int next_dist = state.sum_dist;
				DIR next_dir = state.dir;

				if(min_dist[next_node][state.dir] > next_dist){

					min_dist[next_node][state.dir] = next_dist;
					Q.push(State(next_node,next_dist,true,next_dir));
				}

			}else{ //元々の方向には行けない

				//■枝分かれ■

				int next_node = G[state.node][state.dir];
				int next_dist = state.sum_dist;
				DIR next_dir = state.dir;

				//上
				if((state.dir == to_U || state.dir == to_RU || state.dir == to_LU) && G[state.node][to_U] != -1 && ON_WALL[state.node][to_U]){

					next_node = G[state.node][to_U];

					if(min_dist[next_node][state.dir] > next_dist){ //■元々の方向でminを取る■

						min_dist[next_node][state.dir] = next_dist;
						Q.push(State(next_node,next_dist,true,next_dir));
					}
				}

				//右
				if((state.dir == to_R || state.dir == to_RU || state.dir == to_RD) && G[state.node][to_R] != -1 && ON_WALL[state.node][to_R]){

					next_node = G[state.node][to_R];

					if(min_dist[next_node][state.dir] > next_dist){

						min_dist[next_node][state.dir] = next_dist;
						Q.push(State(next_node,next_dist,true,next_dir));
					}
				}
				//左
				if((state.dir == to_L || state.dir == to_LU || state.dir == to_LD) && G[state.node][to_L] != -1 && ON_WALL[state.node][to_L]){

					next_node = G[state.node][to_L];

					if(min_dist[next_node][state.dir] > next_dist){

						min_dist[next_node][state.dir] = next_dist;
						Q.push(State(next_node,next_dist,true,next_dir));
					}
				}
				//下
				if((state.dir == to_D || state.dir == to_LD || state.dir == to_RD) && G[state.node][to_D] != -1 && ON_WALL[state.node][to_D]){

					next_node = G[state.node][to_D];

					if(min_dist[next_node][state.dir] > next_dist){

						min_dist[next_node][state.dir] = next_dist;
						Q.push(State(next_node,next_dist,true,next_dir));
					}
				}
			}
		}
	}
}

int main(){

	while(true){

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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 4592
final_rank: 2

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <map>
#include <queue>
using namespace std;

const double EPS = 1e-6;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(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;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}
bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

vector<vector<vector<int> > > make_graph(vector<L>& lines, VP &poly, P s, P g){
    VP plist;
    int ls = lines.size();
    vector<VP> cp(ls);
    for(int i=0; i<ls; i++){
        for(int j=i+1; j<ls; j++){
            if(!isParallel(lines[i], lines[j])){
                P cpij = crosspointLL(lines[i], lines[j]);
                if(in_poly(cpij, poly) == -1) continue;
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());
    for(int i=0; i<(int)plist.size(); i++){
        if(plist[i] == s) swap(plist[i], plist[0]);
        if(plist[i] == g) swap(plist[i], plist[1]);
    }
    
    //make convmap (普通にdoubleをキーにすると事故るので、比較関数は誤差ありを使う)
    map<P, int> conv;
    for(int i=0; i<(int)plist.size(); i++){
        conv[plist[i]] = i;
    }

    P dir8[8] = {P(1,0), P(1,1), P(0,1), P(-1,1), P(-1,0), P(-1,-1), P(0,-1), P(1,-1)};
    int n = plist.size();
    //graph[点][向き] = 到達可能点リスト
    vector<vector<vector<int> > > graph(n, vector<vector<int> >(8));
    for(int i=0; i<ls; i++){
        int d=-1; //cp[i][0] から cp[i][1] に進む方向
        for(int j=0; j<8; j++){
            if(intersectSP(L(0, 1e5*dir8[j]), cp[i][1] -cp[i][0])){
                d = j;
                break;
            }
        }

        for(int j=0; j<(int)cp[i].size()-1; j++){
            if(in_poly((cp[i][j] +cp[i][j+1])/2.0, poly) == -1) continue;
            graph[conv[cp[i][j]]][d].push_back(conv[cp[i][j+1]]);
            graph[conv[cp[i][j+1]]][(d+4)%8].push_back(conv[cp[i][j]]);
        }
    }
    
    //壁伝いの移動
    for(int i=0; i<n; i++){
        for(int j=1; j<8; j+=2){
            //壁にぶつかる
            if(in_poly(plist[i]+(0.1*dir8[j]), poly) != -1) continue;
            //かつ壁づたいに動ける
            if(!graph[i][(j+1)%8].empty()){
                graph[i][j].push_back(graph[i][(j+1)%8][0]);
            }
            if(!graph[i][(j+7)%8].empty()){
                graph[i][j].push_back(graph[i][(j+7)%8][0]);
            }
        }
    }
    return graph;
}

int dijkstra(vector<vector<vector<int> > > &graph){
    struct info{
        int v,d,c;
        info(int v, int d, int c):v(v),d(d),c(c){}
        info(){}
        bool operator<(const info &a) const{
            return c > a.c;
        }
    };
    const int inf = 1e9;

    int n = graph.size();
    priority_queue<info> wait;
    vector<vector<int> > mincost(n, vector<int>(8, inf));
    for(int d=0; d<8; d++){
        wait.push(info(0, d, 1));
        mincost[0][d] = 1;
    }
    int ans = inf;
    while(!wait.empty()){
        int v = wait.top().v;
        int d = wait.top().d;
        int c = wait.top().c;
        wait.pop();
        if(c > mincost[v][d]) continue;
        if(v == 1){
            ans = c;
            break;
        }

        for(int nd=0; nd<8; nd++){
            int nc = (d==nd)? c: c+1;
            for(int i=0; i<(int)graph[v][nd].size(); i++){
                int nv = graph[v][nd][i];
                if(nc < mincost[nv][nd]){
                    mincost[nv][nd] = nc;
                    wait.push(info(nv, nd, nc));
                }
            }
        }
    }
    return ans;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;

        //get input
        int sx,sy,gx,gy;
        cin >> sx >> sy >> gx >> gy;
        P s(sx, sy), g(gx, gy);
        VP poly(n);
        for(int i=0; i<n; i++){
            int x,y;
            cin >> x >> y;
            poly[i] = P(x, y);
        }

        vector<L> lines;
        P dir4[4] = {P(0,1), P(1,1), P(1,0), P(1,-1)};
        for(int i=0; i<n; i++){
            for(int d=0; d<4; d++){
                lines.push_back(L(poly[i], poly[i]+dir4[d]));
            }
        }
        for(int d=0; d<4; d++){
            lines.push_back(L(s, s+dir4[d]));
            lines.push_back(L(g, g+dir4[d]));
        }

        vector<vector<vector<int> > > graph = make_graph(lines, poly, s, g);
        cout << dijkstra(graph) << endl;
    }   
    return 0;
}
accuracy: 1
time_ms: 1140
memory_kb: 9336
final_rank: 3

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <map>
#include <queue>
using namespace std;

const double EPS = 1e-6;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(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;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}
bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

vector<vector<vector<int> > > make_graph(vector<L>& lines, VP &poly, P s, P g){
    VP plist;
    int ls = lines.size();
    vector<VP> cp(ls);
    for(int i=0; i<ls; i++){
        for(int j=i+1; j<ls; j++){
            if(!isParallel(lines[i], lines[j])){
                P cpij = crosspointLL(lines[i], lines[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());
    for(int i=0; i<(int)plist.size(); i++){
        if(plist[i] == s) swap(plist[i], plist[0]);
        if(plist[i] == g) swap(plist[i], plist[1]);
    }
    
    //make convmap (普通にdoubleをキーにすると事故るので、比較関数は誤差ありを使う)
    map<P, int> conv;
    for(int i=0; i<(int)plist.size(); i++){
        conv[plist[i]] = i;
    }

    P dir8[8] = {P(1,0), P(1,1), P(0,1), P(-1,1), P(-1,0), P(-1,-1), P(0,-1), P(1,-1)};
    int n = plist.size();
    //graph[点][向き] = 到達可能点リスト
    vector<vector<vector<int> > > graph(n, vector<vector<int> >(8));
    for(int i=0; i<ls; i++){
        int d=-1; //cp[i][0] から cp[i][1] に進む方向
        for(int j=0; j<8; j++){
            if(intersectSP(L(0, 1e5*dir8[j]), cp[i][1] -cp[i][0])){
                d = j;
                break;
            }
        }

        for(int j=0; j<(int)cp[i].size()-1; j++){
            if(in_poly((cp[i][j] +cp[i][j+1])/2.0, poly) == -1) continue;
            graph[conv[cp[i][j]]][d].push_back(conv[cp[i][j+1]]);
            graph[conv[cp[i][j+1]]][(d+4)%8].push_back(conv[cp[i][j]]);
        }
    }
    
    //壁伝いの移動
    for(int i=0; i<n; i++){
        for(int j=1; j<8; j+=2){
            //壁にぶつかる
            if(in_poly(plist[i]+(0.1*dir8[j]), poly) != -1) continue;
            //かつ壁づたいに動ける
            if(!graph[i][(j+1)%8].empty()){
                graph[i][j].push_back(graph[i][(j+1)%8][0]);
            }
            if(!graph[i][(j+7)%8].empty()){
                graph[i][j].push_back(graph[i][(j+7)%8][0]);
            }
        }
    }
    return graph;
}

int dijkstra(vector<vector<vector<int> > > &graph){
    struct info{
        int v,d,c;
        info(int v, int d, int c):v(v),d(d),c(c){}
        info(){}
        bool operator<(const info &a) const{
            return c > a.c;
        }
    };
    const int inf = 1e9;

    int n = graph.size();
    priority_queue<info> wait;
    vector<vector<int> > mincost(n, vector<int>(8, inf));
    for(int d=0; d<8; d++){
        wait.push(info(0, d, 1));
        mincost[0][d] = 1;
    }
    int ans = inf;
    while(!wait.empty()){
        int v = wait.top().v;
        int d = wait.top().d;
        int c = wait.top().c;
        wait.pop();
        if(c > mincost[v][d]) continue;
        if(v == 1){
            ans = c;
            break;
        }

        for(int nd=0; nd<8; nd++){
            int nc = (d==nd)? c: c+1;
            for(int i=0; i<(int)graph[v][nd].size(); i++){
                int nv = graph[v][nd][i];
                if(nc < mincost[nv][nd]){
                    mincost[nv][nd] = nc;
                    wait.push(info(nv, nd, nc));
                }
            }
        }
    }
    return ans;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;

        //get input
        int sx,sy,gx,gy;
        cin >> sx >> sy >> gx >> gy;
        P s(sx, sy), g(gx, gy);
        VP poly(n);
        for(int i=0; i<n; i++){
            int x,y;
            cin >> x >> y;
            poly[i] = P(x, y);
        }

        vector<L> lines;
        P dir4[4] = {P(0,1), P(1,1), P(1,0), P(1,-1)};
        for(int i=0; i<n; i++){
            for(int d=0; d<4; d++){
                lines.push_back(L(poly[i], poly[i]+dir4[d]));
            }
        }
        for(int d=0; d<4; d++){
            lines.push_back(L(s, s+dir4[d]));
            lines.push_back(L(g, g+dir4[d]));
        }

        vector<vector<vector<int> > > graph = make_graph(lines, poly, s, g);
        cout << dijkstra(graph) << endl;
    }   
    return 0;
}
accuracy: 1
time_ms: 1440
memory_kb: 14576
final_rank: 4

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <map>
#include <queue>
using namespace std;

const double EPS = 1e-6;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(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;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}
bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

//多角形内部で、pから8方向に伸ばした線分のリストを取得
vector<L> get_range(P p, const VP& poly){
    P dir4[4] = {P(0,1), P(1,1), P(1,0), P(1,-1)};
    int n = poly.size();
    vector<L> res;
    for(int d=0; d<4; d++){
        L range;
        for(int sign=-1; sign<=1; sign+=2){
            //pに近いほうから交点をすべて列挙
            VP plist;
            L hline(p, p + sign*1e5*dir4[d]);
            for(int i=0; i<n; i++){
                L edge(poly[i], poly[(i+1)%n]);
                if(!isParallel(hline, edge) && intersectSS(hline, edge)){
                    plist.push_back(crosspointLL(hline, edge));
                }
            }
            sort(plist.begin(), plist.end());
            plist.erase(unique(plist.begin(), plist.end()), plist.end());
            if(abs(p -plist[0]) > abs(p -plist.back())){
                reverse(plist.begin(), plist.end());
            }

            //伸ばせるところまで伸ばす
            P lim = plist[0];
            for(int i=1; i<(int)plist.size(); i++){
                if(in_poly((plist[i-1] +plist[i]) /2.0, poly) == -1){
                    break;
                }
                lim = plist[i];
            }
            range[(sign+1)/2] = lim;
        }
        if(range[0] != range[1]){
            res.push_back(range);
        }
    }
    return res;
}

vector<vector<vector<int> > > make_graph(vector<L>& lines, VP &poly, P s, P g){
    VP plist;
    int ls = lines.size();
    vector<VP> cp(ls);
    for(int i=0; i<ls; i++){
        for(int j=i+1; j<ls; j++){
            if(!isParallel(lines[i], lines[j]) && intersectSS(lines[i], lines[j])){
                P cpij = crosspointLL(lines[i], lines[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());
    for(int i=0; i<(int)plist.size(); i++){
        if(plist[i] == s) swap(plist[i], plist[0]);
        if(plist[i] == g) swap(plist[i], plist[1]);
    }
    
    //make convmap (普通にdoubleをキーにすると事故るので、比較関数は誤差ありを使う)
    map<P, int> conv;
    for(int i=0; i<(int)plist.size(); i++){
        conv[plist[i]] = i;
    }

    P dir8[8] = {P(1,0), P(1,1), P(0,1), P(-1,1), P(-1,0), P(-1,-1), P(0,-1), P(1,-1)};
    int n = plist.size();
    //graph[点][向き] = 到達可能点リスト
    vector<vector<vector<int> > > graph(n, vector<vector<int> >(8));
    for(int i=0; i<ls; i++){
        int d=-1; //cp[i][0] から cp[i][1] に進む方向
        for(int j=0; j<8; j++){
            if(intersectSP(L(0, 1e5*dir8[j]), cp[i][1] -cp[i][0])){
                d = j;
                break;
            }
        }

        for(int j=0; j<(int)cp[i].size()-1; j++){
            graph[conv[cp[i][j]]][d].push_back(conv[cp[i][j+1]]);
            graph[conv[cp[i][j+1]]][(d+4)%8].push_back(conv[cp[i][j]]);
        }
    }
    
    //壁伝いの移動
    for(int i=0; i<n; i++){
        for(int j=1; j<8; j+=2){
            //壁にぶつかる
            if(in_poly(plist[i]+(0.1*dir8[j]), poly) != -1) continue;
            //かつ壁づたいに動ける
            if(!graph[i][(j+1)%8].empty()){
                graph[i][j].push_back(graph[i][(j+1)%8][0]);
            }
            if(!graph[i][(j+7)%8].empty()){
                graph[i][j].push_back(graph[i][(j+7)%8][0]);
            }
        }
    }
    return graph;
}

int dijkstra(vector<vector<vector<int> > > &graph){
    struct info{
        int v,d,c;
        info(int v, int d, int c):v(v),d(d),c(c){}
        info(){}
        bool operator<(const info &a) const{
            return c > a.c;
        }
    };
    const int inf = 1e9;

    int n = graph.size();
    priority_queue<info> wait;
    vector<vector<int> > mincost(n, vector<int>(8, inf));
    for(int d=0; d<8; d++){
        wait.push(info(0, d, 1));
        mincost[0][d] = 1;
    }
    int ans = inf;
    while(!wait.empty()){
        int v = wait.top().v;
        int d = wait.top().d;
        int c = wait.top().c;
        wait.pop();
        if(c > mincost[v][d]) continue;
        if(v == 1){
            ans = c;
            break;
        }

        for(int nd=0; nd<8; nd++){
            int nc = (d==nd)? c: c+1;
            for(int i=0; i<(int)graph[v][nd].size(); i++){
                int nv = graph[v][nd][i];
                if(nc < mincost[nv][nd]){
                    mincost[nv][nd] = nc;
                    wait.push(info(nv, nd, nc));
                }
            }
        }
    }
    return ans;
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;

        //get input
        int sx,sy,gx,gy;
        cin >> sx >> sy >> gx >> gy;
        P s(sx, sy), g(gx, gy);
        VP poly(n);
        for(int i=0; i<n; i++){
            int x,y;
            cin >> x >> y;
            poly[i] = P(x, y);
        }

        //線分リスト
        vector<L> lines;
        for(int i=0; i<n; i++){
            vector<L> range = get_range(poly[i], poly);
            lines.insert(lines.end(), range.begin(), range.end());
        }
        {
            vector<L> range = get_range(s, poly);
            lines.insert(lines.end(), range.begin(), range.end());
            range = get_range(g, poly);
            lines.insert(lines.end(), range.begin(), range.end());
        }
        sort(lines.begin(), lines.end());
        lines.erase(unique(lines.begin(), lines.end()), lines.end());

        vector<vector<vector<int> > > graph = make_graph(lines, poly, s, g);
        
        cout << dijkstra(graph) << endl;
    }   
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3496
final_rank: 1