Problem:
Problem H:
Cornering at Poles
You are invited to a robot contest. In the contest, you are given a disc-shaped robot that is placed on a flat field. A set of poles are standing on the ground. The robot can move in all directions, but must avoid the poles. However, the robot can make turns around the poles touching them.
Your mission is to find the shortest path of the robot to reach the given goal position. The length of the path is defined by the moving distance of the center of the robot. Figure H.1 shows the shortest path for a sample layout. In this figure, a red line connecting a pole pair means that the distance between the poles is shorter than the diameter of the robot and the robot cannot go through between them.
Figure H.1. The shortest path for a sample layout
Input
The input consists of a single test case.
$N$ $G_x$ $G_y$
$x_1$ $y_1$
.
.
.
$x_N$ $y_N$
The first line contains three integers. $N$ represents the number of the poles ($1 \leq N \leq 8$). $(G_x, G_y)$ represents the goal position. The robot starts with its center at $(0, 0)$, and the robot accomplishes its task when the center of the robot reaches the position $(G_x, G_y)$. You can assume that the starting and goal positions are not the same.
Each of the following $N$ lines contains two integers. $(x_i, y_i)$ represents the standing position of the $i$-th pole. Each input coordinate of $(G_x, G_y)$ and $(x_i, y_i)$ is between $−1000$ and $1000$, inclusive. The radius of the robot is $100$, and you can ignore the thickness of the poles. No pole is standing within a $100.01$ radius from the starting or goal positions. For the distance $d_{i,j}$ between the $i$-th and $j$-th poles $(i \ne j)$, you can assume $1 \leq d_{i,j} < 199.99$ or $200.01 < d_{i,j}$.
Figure H.1 shows the shortest path for Sample Input 1 below, and Figure H.2 shows the shortest paths for the remaining Sample Inputs.
Figure H.2. The shortest paths for the sample layouts
Output
Output the length of the shortest path to reach the goal. If the robot cannot reach the goal, output 0.0. The output should not contain an error greater than 0.0001.
Sample Input 1
8 900 0
40 100
70 -80
350 30
680 -20
230 230
300 400
530 130
75 -275
Sample Output 1
1210.99416
Sample Input 2
1 0 200
120 0
Sample Output 2
200.0
Sample Input 3
3 110 110
0 110
110 0
200 10
Sample Output 3
476.95048
Sample Input 4
4 0 200
90 90
-90 90
-90 -90
90 -90
Sample Output 4
0.0
Sample Input 5
2 0 -210
20 -105
-5 -105
Sample Output 5
325.81116
Sample Input 6
8 680 -50
80 80
80 -100
480 -120
-80 -110
240 -90
-80 100
-270 100
-420 -20
Sample Output 6
1223.53071

Submitted solutions:

code_snippet: #include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define eps 1.0e-9
#define sgn(f) ((f)<(-eps)?-1:((f)>eps))
using namespace std;
const double pi=acos(-1.0);
int n,N;
double e[999][999];
struct  point
{
	double x,y;
	point(double _x=0,double _y=0):x(_x),y(_y){};
    point operator + (point a) {return point(x+a.x, y+a.y);}
    point operator - (point a) {return point(x-a.x, y-a.y);}
    point operator * (double p) {return point(x*p, y*p);}
    point operator / (double p) {return point(x/p, y/p);}
    bool operator == (point a) {return sgn(x-a.x)==0&&sgn(y-a.y)==0;}
}robot,target,p[2333];
struct circle
{
    double r;
    point c;
    point GetPoint(double a) {return point(c.x+cos(a)*r,c.y+sin(a)*r);}
}pole[10];
typedef point Vector;
double dmult(Vector a,Vector b) {return a.x*b.x+a.y*b.y;}
double xmult(Vector a,Vector b) {return a.x*b.y-a.y*b.x;}
double xmult(point a,point b,point o) {return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);}
Vector xmult(Vector a) {return Vector(a.y,-a.x);}
double dis(Vector a) {return sqrt(a.x*a.x+a.y*a.y);}
double dis(point a,point b) {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
double angle(Vector v) {return atan2(v.y,v.x);}
double intersection_angle(Vector a,Vector b) {return acos(dmult(a,b)/dis(a)/dis(b));}
double DistanceToLine(point p,point a,point b) {return fabs(xmult(b-a,p-a))/dis(b-a);}
int GetTangents(point p,circle c,point *pt)
{
    Vector u=p-c.c;
    double d=dmult(u,u),rr=c.r*c.r;
    int flag=sgn(d-rr);
    if(flag<0) return 0;
    else if(flag==0)
         {
         	pt[0]=p;
            return 1;
         }
         else
         {
         	Vector v=xmult(u);
            pt[0]=(c.c*d+u*rr-v*c.r*sqrt(d-rr))/d;
            pt[1]=(c.c*d+u*rr+v*c.r*sqrt(d-rr))/d;
            return 2;
         }
}
int GetTangents(circle A,circle B,point *a,point *b)
{
    int cnt=0;
    if(sgn(A.r-B.r)<0)
    {
        swap(a,b);
        swap(A,B);
    }
    double d2=dmult(A.c-B.c,A.c-B.c),rdiff=A.r-B.r,rsum=A.r+B.r;
    if(sgn(d2-rdiff*rdiff)<0) return 0;
    double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    if(sgn(d2)==0&&sgn(A.r-B.r)==0) return -1;
    if(sgn(d2-rdiff*rdiff)==0)
    {
        a[cnt]=A.GetPoint(base);
        b[cnt]=B.GetPoint(base);
        cnt++;
        return 1;
    }
    double ang=acos((A.r-B.r)/sqrt(d2));
    a[cnt]=A.GetPoint(base+ang);b[cnt]=B.GetPoint(base+ang);cnt++;
    a[cnt]=A.GetPoint(base-ang);b[cnt]=B.GetPoint(base-ang);cnt++;
    if(sgn(d2-rsum*rsum)==0)
    {
        a[cnt]=A.GetPoint(base);
        b[cnt]=B.GetPoint(pi+base);
        cnt++;
    }
    else if(sgn(d2-rsum*rsum)>0)
         {
             double ang=acos((A.r+B.r)/sqrt(d2));
             a[cnt]=A.GetPoint(base+ang);b[cnt]=B.GetPoint(pi+base+ang);cnt++;
             a[cnt]=A.GetPoint(base-ang);b[cnt]=B.GetPoint(pi+base-ang);cnt++;
         }
    return cnt;
}
bool isonsegment(point &a,point &b,point &c)
{
    if(sgn(xmult(a,b,c))) return false;
    if(sgn(c.x-min(a.x,b.x))<0||sgn(c.x-max(a.x,b.x))>0) return false;
    if(sgn(c.y-min(a.y,b.y))<0||sgn(c.y-max(a.y,b.y))>0) return false;
    return true;
}
point GetLineProjection(point p,point a,point b)
{
    if(sgn(xmult(p-a,p-b))==0) return p;
    return a+(b-a)*(dmult(b-a,p-a)/dmult(b-a,b-a));
}
int GetLineCircleIntersection(point a,point b,circle c,point *pt)
{
    double d=DistanceToLine(c.c,a,b);
    if(sgn(d-c.r)>0) return 0;
    point p=GetLineProjection(c.c,a,b);
    Vector v=(b-a)/dis(b-a);
    double l=sqrt(c.r*c.r-d*d);
    pt[0]=p-v*l;
    pt[1]=p+v*l;
    if(sgn(d-c.r)==0) return 1;
    else return 2;
}
int GetCircleCircleIntersection(circle a,circle b,point *p)
{
    double d=dmult(a.c-b.c,a.c-b.c);
    if(sgn(d)==0)
    {
        if(sgn(a.r-b.r)==0) return -1;
        else return 0;
    }
    if(sgn((a.r+b.r)*(a.r+b.r)-d)<0) return 0;
    if(sgn((a.r-b.r)*(a.r-b.r)-d)>0) return 0;
    double alpha=angle(b.c-a.c);
    double theta=acos((a.r*a.r+d-b.r*b.r)/(2*sqrt(d)*a.r));
    if(sgn(theta)==0) theta=0;
    p[0]=a.GetPoint(alpha-theta);
    p[1]=a.GetPoint(alpha+theta);
    if(sgn(theta)==0) return 1;
    else return 2;
}

int CheckDirection(Vector v,Vector u)
{
	if(sgn(xmult(u,v))==0)
	{
		if(sgn(dmult(u,v))>=0) return 1;
		else return -1;
	}
	else return 0;
}

bool CheckIn(Vector v,Vector L,Vector R)
{
	if(CheckDirection(L,R)==1||CheckDirection(v,L)==1||CheckDirection(v,R)==1) return false;
	if(sgn(xmult(L,R))>=0)	return sgn(xmult(L,v))>0&&sgn(xmult(v,R))>0;
	else return sgn(xmult(v,L))<=0||sgn(xmult(R,v))<=0;
}
bool CheckIntersection(Vector vl,Vector vr,Vector ul,Vector ur)
{
	if(CheckDirection(vl,vr)==1||CheckDirection(ul,ur)==1) return false;
	if(CheckIn(vl,ul,ur)||CheckIn(vr,ul,ur)) return true;
	if(CheckIn(ul,vl,vr)||CheckIn(ur,vl,vr)) return true;
	return CheckDirection(vl,ul)&&CheckDirection(vr,ur);
}
double GetArcLength(circle c,point a,point b)
{
	if(a==b) return 2*pi*c.r;
	Vector va=a-c.c,vb=b-c.c;
	double alpha=intersection_angle(va,vb);
	if(sgn(xmult(va,vb))<0) alpha=2*pi-alpha;
	return alpha*c.r;
}
bool check(point a,point b)
{
	point pt[5];
	Vector v=b-a;
	double dv=dmult(v,v),t[5];
	for(int i=0;i<n;++i)
	{
		int cnt=GetLineCircleIntersection(a,b,pole[i],pt);
		if(cnt<=1) continue;
		t[0]=dmult(pt[0]-a,v)/dv;
		t[1]=dmult(pt[1]-a,v)/dv;
		if(sgn(t[0]-t[1])>0) swap(t[0],t[1]);
		t[0]=max(t[0],0.0);
		t[0]=min(t[0],1.0);
		t[1]=max(t[1],0.0);
		t[1]=min(t[1],1.0);
		if(sgn(t[0]-t[1])<0) return false;
	}
	return true;
}
bool cmp(const point &a,const point &b)
{
	if(sgn(a.y)>=0)
	{
		if(sgn(b.y)<0) return true;
		else if(sgn(xmult(a,b))!=0) return sgn(xmult(a,b))>0;
			 else return sgn(a.x)>0;
	}
	else
	{
		if(sgn(b.y)>=0) return false;
		else return sgn(xmult(a,b))>0;
	}
}
void AddPoint(point a)
{
	for(int i=0;i<N;++i) if(a==p[i]) return ;
	p[N++]=a;
}
int FindPoint(point a)
{
	for(int i=0;i<N;++i) if(a==p[i]) return i;
	printf("FUCK!\n");
	return -1;
}
void init()
{
    N=0;
    AddPoint(robot);
    AddPoint(target);
    point pt[10];
    int cnt;
    for(int i=0;i<n;++i)
    {
        cnt=GetTangents(robot,pole[i],pt);
        for(int j=0;j<cnt;++j) AddPoint(pt[j]);
    }
    for(int i=0;i<n;++i)
    {
        cnt=GetTangents(target,pole[i],pt);
        for(int j=0;j<cnt;++j) AddPoint(pt[j]);
    }
    for(int i=0;i<n;++i)
    {
    	AddPoint(pole[i].c+Vector(pole[i].r,0));
        for(int j=i+1;j<n;++j)
        {
            point pt1[10],pt2[10];
            cnt=GetTangents(pole[i],pole[j],pt1,pt2);
            for(int k=0;k<cnt;++k)
            {
                AddPoint(pt1[k]);
                AddPoint(pt2[k]);
            }
            cnt=GetCircleCircleIntersection(pole[i],pole[j],pt);
            for(int k=0;k<cnt;++k) AddPoint(pt[k]);
        }
    }
}
void BuildGraph()
{
	for(int i=0;i<N;++i)
		for(int j=0;j<N;++j) e[i][j]=-1.0;
	for(int i=0;i<N;++i)
		for(int j=i+1;j<N;++j) if(check(p[i],p[j])) e[i][j]=e[j][i]=dis(p[i],p[j]);
	point pt[2333],tp[10],tpp[10];
	int m=0,cnt;
	for(int i=0;i<n;++i)
	{
		m=0;
		pt[m++]=pole[i].c+Vector(pole[i].r,0);
		cnt=GetTangents(robot,pole[i],tp);
		for(int j=0;j<cnt;++j)
		{
			bool ok=true;
			for(int k=0;k<m;++k) if(pt[k]==tp[j]) {ok=false;break;}
			if(ok) pt[m++]=tp[j];
		}
		cnt=GetTangents(target,pole[i],tp);
		for(int j=0;j<cnt;++j)
		{
			bool ok=true;
			for(int k=0;k<m;++k) if(pt[k]==tp[j]) {ok=false;break;}
			if(ok) pt[m++]=tp[j];
		}
		for(int j=0;j<n;++j)
		{
		    if(i==j) continue;
			cnt=GetTangents(pole[i],pole[j],tp,tpp);
			for(int k=0;k<cnt;++k)
			{
				bool ok=true;
				for(int t=0;t<m;++t) if(pt[t]==tp[k]) {ok=false;break;}
				if(ok) pt[m++]=tp[k];
			}
			cnt=GetCircleCircleIntersection(pole[i],pole[j],tp);
			for(int k=0;k<cnt;++k)
			{
				bool ok=true;
				for(int t=0;t<m;++t) if(pt[t]==tp[k]) {ok=false;break;}
				if(ok) pt[m++]=tp[k];
			}
		}
		for(int j=0;j<m;++j) pt[j]=pt[j]-pole[i].c;
		sort(pt,pt+m,cmp);
		pt[m]=pt[0];
		for(int j=0;j<m;++j)
		{
			bool ok=true;
			for(int k=0;k<n;++k)
			{
			    if(k==i) continue;
				cnt=GetCircleCircleIntersection(pole[i],pole[k],tp);
				if(cnt<2) continue;
				if(CheckIntersection(tp[0]-pole[i].c,tp[1]-pole[i].c,pt[j],pt[j+1])) {ok=false;break;}
			}
			if(ok)
			{
				int u=FindPoint(pole[i].c+pt[j]),v=FindPoint(pole[i].c+pt[j+1]);
				double w=GetArcLength(pole[i],pt[j]+pole[i].c,pt[j+1]+pole[i].c);
				if(sgn(e[u][v]+1)<=0) e[u][v]=w;
				else e[u][v]=min(e[u][v],w);
				e[v][u]=e[u][v];
			}
		}
	}
}
void Floyd()
{
	for(int k=0;k<N;++k)
		for(int i=0;i<N;++i)
		{
			if(sgn(e[i][k]+1)<=0) continue;
			for(int j=0;j<N;++j)
			{
				if(sgn(e[k][j]+1)<=0) continue;
				if(sgn(e[i][j]+1)<=0||sgn(e[i][j]-e[i][k]-e[k][j])>0) e[i][j]=e[i][k]+e[k][j];
			}
		}
}
int main()
{
	//freopen("in.txt","r",stdin);
	robot=point(0,0);
	while(scanf("%d%lf%lf",&n,&target.x,&target.y)==3)
	{
		for(int i=0;i<n;++i)
		{
			scanf("%lf%lf",&pole[i].c.x,&pole[i].c.y);
			pole[i].r=100;
		}
		init();
		BuildGraph();
		Floyd();
		if(sgn(e[0][1]+1)<=0) printf("0.0\n");
		else printf("%.5f\n",e[0][1]);
	}
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 7840
final_rank: 16

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
using namespace std;

const double PI = 3.14159265358979;

struct Point {
	double px, py;
};

struct Circle {
	Point c;
	double r = 100.0;
};

Point operator+(const Point &a1, const Point &a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point &a1, const Point &a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point &a1, const double &a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

// Absolute Value
double ABS(Point A1) {
	return sqrt(A1.px * A1.px + A1.py * A1.py);
}

// Return Polar Point
Point Polar(double r, double theta) {
	return Point{ r * cos(theta), r * sin(theta) };
}

// Tangent: Point and Circle
vector<Point> Tangent_PC(Point A1, Circle A2) {
	double d = ABS(A1 - A2.c);
	double r = A2.r;
	double Theta1 = asin(r / d);
	double Theta2 = atan2((A2.c - A1).py, (A2.c - A1).px);
	Point P1 = A1 + Polar(sqrt(d * d - r * r), Theta2 + Theta1);
	Point P2 = A1 + Polar(sqrt(d * d - r * r), Theta2 - Theta1);
	return vector<Point>{P1, P2};
}

// Tangent: Circle and Circle
pair<vector<Point>, vector<Point>> Tangent_CC(Circle A1, Circle A2) {
	vector<Point> Ret1, Ret2;
	double d = ABS(A2.c - A1.c);
	double r = A1.r;
	double Theta = atan2((A2.c - A1.c).py, (A2.c - A1.c).px);
	Ret1.push_back(A1.c + Polar(r, Theta + PI / 2.0));
	Ret1.push_back(A1.c + Polar(r, Theta - PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta + PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta - PI / 2.0));
	if (ABS(A1.c - A2.c) < 200.0) return make_pair(Ret1, Ret2);
	
	// Latter Half
	Point Mid = (A1.c + A2.c) * 0.5;
	double Theta2 = asin(2.0 * r / d);
	double dt = sqrt(0.25 * d * d - r * r);
	Ret1.push_back(Mid + Polar(dt, PI + Theta + Theta2));
	Ret1.push_back(Mid + Polar(dt, PI + Theta - Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta + Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta - Theta2));
	return make_pair(Ret1, Ret2);
}

// Dot
double dot(Point A1, Point A2) {
	return A1.px * A2.px + A1.py * A2.py;
}

// Cross
double crs(Point A1, Point A2) {
	return A1.px * A2.py - A1.py * A2.px;
}

// Distance between segment A1A2 and Point A3
double DistSeg(Point A1, Point A2, Point A3) {
	if (dot(A2 - A1, A3 - A1) < 0.0) return ABS(A3 - A1);
	if (dot(A1 - A2, A3 - A2) < 0.0) return ABS(A3 - A2);
	double val = abs(crs(A2 - A1, A3 - A1));
	return val / ABS(A2 - A1);
}

int N; Point Start, Goal;
Circle Pole[19];
vector<pair<Point, int>> Cand;
double dist[1009][1009];

// Check if P1->P2 is valid for "straight move"
bool Passable(Point P1, Point P2) {
	for (int i = 1; i <= N; i++) {
		double dst = DistSeg(P1, P2, Pole[i].c);
		if (dst <= Pole[i].r - 1e-4) return false;
	}
	return true;
}

// Distance between angle1 and angle2
double DistAngle(double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	return 100.0 * (angle2 - angle1);
}

// Is it passable from angle1 to angle2 in circle idx?
bool PassCircle(int idx, double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	Point P1 = Pole[idx].c + Polar(100.0, angle1);
	Point P2 = Pole[idx].c + Polar(100.0, angle2);
	for (int i = 1; i <= N; i++) {
		if (ABS(P1 - Pole[i].c) < 100.0 - 1.0e-4) return false;
		if (ABS(P2 - Pole[i].c) < 100.0 - 1.0e-4) return false;
	}
	for (int i = 1; i <= N; i++) {
		if (i == idx) continue;
		Point Diff = Pole[i].c - Pole[idx].c; if (ABS(Diff) > 200.0 - 1.0e-4) continue;
		double angle3 = atan2(Diff.py, Diff.px);
		while (angle1 > angle3) angle3 += 2.0 * PI;
		if (angle3 <= angle2) return false;
	}
	return true;
}

int main() {
	// Input
	cin >> N >> Goal.px >> Goal.py;
	for (int i = 1; i <= N; i++) cin >> Pole[i].c.px >> Pole[i].c.py;
	Start.px = 0.0;
	Start.py = 0.0;
	
	// Add to Candidate
	Cand.push_back(make_pair(Start, -1));
	Cand.push_back(make_pair(Goal, -1));
	for (int i = 1; i <= N; i++) {
		vector<Point> P1 = Tangent_PC(Start, Pole[i]);
		for (Point j : P1) Cand.push_back(make_pair(j, i));
		vector<Point> P2 = Tangent_PC(Goal, Pole[i]);
		for (Point j : P2) Cand.push_back(make_pair(j, i));
	}
	for (int i = 1; i <= N; i++) {
		for (int j = i + 1; j <= N; j++) {
			pair<vector<Point>, vector<Point>> P1 = Tangent_CC(Pole[i], Pole[j]);
			for (Point k : P1.first) Cand.push_back(make_pair(k, i));
			for (Point k : P1.second) Cand.push_back(make_pair(k, j));
		}
	}
	
	// Calculate Distance
	for (int i = 0; i < (int)Cand.size(); i++) {
		for (int j = 0; j < (int)Cand.size(); j++) {
			dist[i][j] = 1e9;
			if (Passable(Cand[i].first, Cand[j].first) == true) {
				double dst = ABS(Cand[i].first - Cand[j].first);
				dist[i][j] = min(dist[i][j], dst);
			}
			if (Cand[i].second == Cand[j].second && i != j && Cand[i].second != -1) {
				Point BASE = Pole[Cand[i].second].c;
				double angle1 = atan2((Cand[i].first - BASE).py, (Cand[i].first - BASE).px);
				double angle2 = atan2((Cand[j].first - BASE).py, (Cand[j].first - BASE).px);
				bool ret1 = PassCircle(Cand[i].second, angle1, angle2);
				bool ret2 = PassCircle(Cand[i].second, angle2, angle1);
				if (ret1 == true) dist[i][j] = min(dist[i][j], DistAngle(angle1, angle2));
				if (ret2 == true) dist[i][j] = min(dist[i][j], DistAngle(angle2, angle1));
			}
		}
		dist[i][i] = 0.0;
	}
	
	// Warshall-Floyd
	for (int k = 0; k < (int)Cand.size(); k++) {
		for (int i = 0; i < (int)Cand.size(); i++) {
			for (int j = 0; j < (int)Cand.size(); j++) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
		}
	}
	
	// Output
	if (dist[0][1] > 1e8) printf("0.0\n");
	else printf("%.12lf\n", dist[0][1]);
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 5732
final_rank: 12

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
using namespace std;

const double PI = 3.14159265358979;

struct Point {
	double px, py;
};

struct Circle {
	Point c;
	double r = 100.0;
};

Point operator+(const Point &a1, const Point &a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point &a1, const Point &a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point &a1, const double &a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

// Absolute Value
double ABS(Point A1) {
	return sqrt(A1.px * A1.px + A1.py * A1.py);
}

// Return Polar Point
Point Polar(double r, double theta) {
	return Point{ r * cos(theta), r * sin(theta) };
}

// Tangent: Point and Circle
vector<Point> Tangent_PC(Point A1, Circle A2) {
	double d = ABS(A1 - A2.c);
	double r = A2.r;
	double Theta1 = asin(r / d);
	double Theta2 = atan2((A2.c - A1).py, (A2.c - A1).px);
	Point P1 = A1 + Polar(sqrt(d * d - r * r), Theta2 + Theta1);
	Point P2 = A1 + Polar(sqrt(d * d - r * r), Theta2 - Theta1);
	return vector<Point>{P1, P2};
}

// Tangent: Circle and Circle
pair<vector<Point>, vector<Point>> Tangent_CC(Circle A1, Circle A2) {
	vector<Point> Ret1, Ret2;
	double d = ABS(A2.c - A1.c);
	double r = A1.r;
	double Theta = atan2((A2.c - A1.c).py, (A2.c - A1.c).px);
	Ret1.push_back(A1.c + Polar(r, Theta + PI / 2.0));
	Ret1.push_back(A1.c + Polar(r, Theta - PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta + PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta - PI / 2.0));
	
	// Latter Half
	Point Mid = (A1.c + A2.c) * 0.5;
	double Theta2 = asin(2.0 * r / d);
	double dt = sqrt(0.25 * d * d - r * r);
	Ret1.push_back(Mid + Polar(dt, PI + Theta + Theta2));
	Ret1.push_back(Mid + Polar(dt, PI + Theta - Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta + Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta - Theta2));
	return make_pair(Ret1, Ret2);
}

// Dot
double dot(Point A1, Point A2) {
	return A1.px * A2.px + A1.py * A2.py;
}

// Cross
double crs(Point A1, Point A2) {
	return A1.px * A2.py - A1.py * A2.px;
}

// Distance between segment A1A2 and Point A3
double DistSeg(Point A1, Point A2, Point A3) {
	if (dot(A2 - A1, A3 - A1) < 0.0) return ABS(A3 - A1);
	if (dot(A1 - A2, A3 - A2) < 0.0) return ABS(A3 - A2);
	double val = abs(crs(A2 - A1, A3 - A1));
	return val / ABS(A2 - A1);
}

int N; Point Start, Goal;
Circle Pole[19];
vector<pair<Point, int>> Cand;
double dist[1009][1009];

// Check if P1->P2 is valid for "straight move"
bool Passable(Point P1, Point P2) {
	for (int i = 1; i <= N; i++) {
		double dst = DistSeg(P1, P2, Pole[i].c);
		if (dst <= Pole[i].r - 1e-4) return false;
	}
	return true;
}

// Distance between angle1 and angle2
double DistAngle(double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	return 100.0 * (angle2 - angle1);
}

// Is it passable from angle1 to angle2 in circle idx?
bool PassCircle(int idx, double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	Point P1 = Pole[idx].c + Polar(100.0, angle1);
	Point P2 = Pole[idx].c + Polar(100.0, angle2);
	for (int i = 1; i <= N; i++) {
		if (ABS(P1 - Pole[i].c) < 100.0 - 1.0e-4) return false;
		if (ABS(P2 - Pole[i].c) < 100.0 - 1.0e-4) return false;
	}
	for (int i = 1; i <= N; i++) {
		if (i == idx) continue;
		Point Diff = Pole[i].c - Pole[idx].c; if (ABS(Diff) > 200.0 - 1.0e-4) continue;
		double angle3 = atan2(Diff.py, Diff.px);
		while (angle1 > angle3) angle3 += 2.0 * PI;
		if (angle3 <= angle2) return false;
	}
	return true;
}

int main() {
	// Input
	cin >> N >> Goal.px >> Goal.py;
	for (int i = 1; i <= N; i++) cin >> Pole[i].c.px >> Pole[i].c.py;
	Start.px = 0.0;
	Start.py = 0.0;
	
	// Add to Candidate
	Cand.push_back(make_pair(Start, -1));
	Cand.push_back(make_pair(Goal, -1));
	for (int i = 1; i <= N; i++) {
		vector<Point> P1 = Tangent_PC(Start, Pole[i]);
		for (Point j : P1) Cand.push_back(make_pair(j, i));
		vector<Point> P2 = Tangent_PC(Goal, Pole[i]);
		for (Point j : P2) Cand.push_back(make_pair(j, i));
	}
	for (int i = 1; i <= N; i++) {
		for (int j = i + 1; j <= N; j++) {
			if (ABS(Pole[i].c - Pole[j].c) < 200.0) continue;
			pair<vector<Point>, vector<Point>> P1 = Tangent_CC(Pole[i], Pole[j]);
			for (Point k : P1.first) Cand.push_back(make_pair(k, i));
			for (Point k : P1.second) Cand.push_back(make_pair(k, j));
		}
	}
	
	// Calculate Distance
	for (int i = 0; i < (int)Cand.size(); i++) {
		for (int j = 0; j < (int)Cand.size(); j++) {
			dist[i][j] = 1e9;
			if (Passable(Cand[i].first, Cand[j].first) == true) {
				double dst = ABS(Cand[i].first - Cand[j].first);
				dist[i][j] = min(dist[i][j], dst);
			}
			if (Cand[i].second == Cand[j].second && i != j && Cand[i].second != -1) {
				Point BASE = Pole[Cand[i].second].c;
				double angle1 = atan2((Cand[i].first - BASE).py, (Cand[i].first - BASE).px);
				double angle2 = atan2((Cand[j].first - BASE).py, (Cand[j].first - BASE).px);
				bool ret1 = PassCircle(Cand[i].second, angle1, angle2);
				bool ret2 = PassCircle(Cand[i].second, angle2, angle1);
				if (ret1 == true) dist[i][j] = min(dist[i][j], DistAngle(angle1, angle2));
				if (ret2 == true) dist[i][j] = min(dist[i][j], DistAngle(angle2, angle1));
			}
		}
		dist[i][i] = 0.0;
	}
	
	// Warshall-Floyd
	for (int k = 0; k < (int)Cand.size(); k++) {
		for (int i = 0; i < (int)Cand.size(); i++) {
			for (int j = 0; j < (int)Cand.size(); j++) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
		}
	}
	
	// Output
	if (dist[0][1] > 1e8) printf("0.0\n");
	else printf("%.12lf\n", dist[0][1]);
	return 0;
}
accuracy: 0.04
time_ms: 10
memory_kb: 5676
final_rank: 18

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
using namespace std;

const double PI = 3.14159265358979;

struct Point {
	double px, py;
};

struct Circle {
	Point c;
	double r = 100.0;
};

Point operator+(const Point &a1, const Point &a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point &a1, const Point &a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point &a1, const double &a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

// Absolute Value
double ABS(Point A1) {
	return sqrt(A1.px * A1.px + A1.py * A1.py);
}

// Return Polar Point
Point Polar(double r, double theta) {
	return Point{ r * cos(theta), r * sin(theta) };
}

// Tangent: Point and Circle
vector<Point> Tangent_PC(Point A1, Circle A2) {
	double d = ABS(A1 - A2.c);
	double r = A2.r;
	double Theta1 = asin(r / d);
	double Theta2 = atan2((A2.c - A1).py, (A2.c - A1).px);
	Point P1 = A1 + Polar(sqrt(d * d - r * r), Theta2 + Theta1);
	Point P2 = A1 + Polar(sqrt(d * d - r * r), Theta2 - Theta1);
	return vector<Point>{P1, P2};
}

// Tangent: Circle and Circle
pair<vector<Point>, vector<Point>> Tangent_CC(Circle A1, Circle A2) {
	vector<Point> Ret1, Ret2;
	double d = ABS(A2.c - A1.c);
	double r = A1.r;
	double Theta = atan2((A2.c - A1.c).py, (A2.c - A1.c).px);
	Ret1.push_back(A1.c + Polar(r, Theta + PI / 2.0));
	Ret1.push_back(A1.c + Polar(r, Theta - PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta + PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta - PI / 2.0));
	
	// Latter Half
	Point Mid = (A1.c + A2.c) * 0.5;
	double Theta2 = asin(2.0 * r / d);
	double dt = sqrt(0.25 * d * d - r * r);
	Ret1.push_back(Mid + Polar(dt, PI + Theta + Theta2));
	Ret1.push_back(Mid + Polar(dt, PI + Theta - Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta + Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta - Theta2));
	return make_pair(Ret1, Ret2);
}

// Dot
double dot(Point A1, Point A2) {
	return A1.px * A2.px + A1.py * A2.py;
}

// Cross
double crs(Point A1, Point A2) {
	return A1.px * A2.py - A1.py * A2.px;
}

// Distance between segment A1A2 and Point A3
double DistSeg(Point A1, Point A2, Point A3) {
	if (dot(A2 - A1, A3 - A1) < 0.0) return ABS(A3 - A1);
	if (dot(A1 - A2, A3 - A2) < 0.0) return ABS(A3 - A2);
	double val = abs(crs(A2 - A1, A3 - A1));
	return val / ABS(A2 - A1);
}

int N; Point Start, Goal;
Circle Pole[19];
vector<pair<Point, int>> Cand;
double dist[1009][1009];

// Check if P1->P2 is valid for "straight move"
bool Passable(Point P1, Point P2) {
	for (int i = 1; i <= N; i++) {
		double dst = DistSeg(P1, P2, Pole[i].c);
		if (dst <= Pole[i].r - 1e-4) return false;
	}
	return true;
}

// Distance between angle1 and angle2
double DistAngle(double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	return 100.0 * (angle2 - angle1);
}

// Is it passable from angle1 to angle2 in circle idx?
bool PassCircle(int idx, double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	Point P1 = Pole[idx].c + Polar(100.0, angle1);
	Point P2 = Pole[idx].c + Polar(100.0, angle2);
	for (int i = 1; i <= N; i++) {
		if (ABS(P1 - Pole[i].c) < 100.0 - 1.0e-4) return false;
		if (ABS(P2 - Pole[i].c) < 100.0 - 1.0e-4) return false;
	}
	for (int i = 1; i <= N; i++) {
		Point Diff = Pole[i].c - Pole[idx].c; if (ABS(Diff) > 200.0 - 1.0e-4) continue;
		double angle3 = atan2(Diff.py, Diff.px);
		while (angle1 > angle3) angle3 += 2.0 * PI;
		if (angle3 <= angle2) return false;
	}
	return true;
}

int main() {
	// Input
	cin >> N >> Goal.px >> Goal.py;
	for (int i = 1; i <= N; i++) cin >> Pole[i].c.px >> Pole[i].c.py;
	Start.px = 0.0;
	Start.py = 0.0;
	
	// Add to Candidate
	Cand.push_back(make_pair(Start, -1));
	Cand.push_back(make_pair(Goal, -1));
	for (int i = 1; i <= N; i++) {
		vector<Point> P1 = Tangent_PC(Start, Pole[i]);
		for (Point j : P1) Cand.push_back(make_pair(j, i));
		vector<Point> P2 = Tangent_PC(Goal, Pole[i]);
		for (Point j : P2) Cand.push_back(make_pair(j, i));
	}
	for (int i = 1; i <= N; i++) {
		for (int j = i + 1; j <= N; j++) {
			if (ABS(Pole[i].c - Pole[j].c) < 200.0) continue;
			pair<vector<Point>, vector<Point>> P1 = Tangent_CC(Pole[i], Pole[j]);
			for (Point k : P1.first) Cand.push_back(make_pair(k, i));
			for (Point k : P1.second) Cand.push_back(make_pair(k, j));
		}
	}
	
	// Calculate Distance
	for (int i = 0; i < (int)Cand.size(); i++) {
		for (int j = 0; j < (int)Cand.size(); j++) {
			dist[i][j] = 1e9;
			if (Passable(Cand[i].first, Cand[j].first) == true) {
				double dst = ABS(Cand[i].first - Cand[j].first);
				dist[i][j] = min(dist[i][j], dst);
			}
			if (Cand[i].second == Cand[j].second && i != j && Cand[i].second != -1) {
				Point BASE = Pole[Cand[i].second].c;
				double angle1 = atan2((Cand[i].first - BASE).py, (Cand[i].first - BASE).px);
				double angle2 = atan2((Cand[j].first - BASE).py, (Cand[j].first - BASE).px);
				bool ret1 = PassCircle(Cand[i].second, angle1, angle2);
				bool ret2 = PassCircle(Cand[i].second, angle2, angle1);
				if (ret1 == true) dist[i][j] = min(dist[i][j], DistAngle(angle1, angle2));
				if (ret2 == true) dist[i][j] = min(dist[i][j], DistAngle(angle2, angle1));
			}
		}
		dist[i][i] = 0.0;
	}
	
	// Warshall-Floyd
	for (int k = 0; k < (int)Cand.size(); k++) {
		for (int i = 0; i < (int)Cand.size(); i++) {
			for (int j = 0; j < (int)Cand.size(); j++) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
		}
	}
	
	// Output
	if (dist[0][1] > 1e8) printf("0.0\n");
	else printf("%.12lf\n", dist[0][1]);
	return 0;
}
accuracy: 0.04
time_ms: 10
memory_kb: 5680
final_rank: 19

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
using namespace std;

const double PI = 3.14159265358979;

struct Point {
	double px, py;
};

struct Circle {
	Point c;
	double r = 100.0;
};

Point operator+(const Point &a1, const Point &a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point &a1, const Point &a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point &a1, const double &a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

// Absolute Value
double ABS(Point A1) {
	return sqrt(A1.px * A1.px + A1.py * A1.py);
}

// Return Polar Point
Point Polar(double r, double theta) {
	return Point{ r * cos(theta), r * sin(theta) };
}

// Tangent: Point and Circle
vector<Point> Tangent_PC(Point A1, Circle A2) {
	double d = ABS(A1 - A2.c);
	double r = A2.r;
	double Theta1 = asin(r / d);
	double Theta2 = atan2((A2.c - A1).py, (A2.c - A1).px);
	Point P1 = A1 + Polar(sqrt(d * d - r * r), Theta2 + Theta1);
	Point P2 = A1 + Polar(sqrt(d * d - r * r), Theta2 - Theta1);
	return vector<Point>{P1, P2};
}

// Tangent: Circle and Circle
pair<vector<Point>, vector<Point>> Tangent_CC(Circle A1, Circle A2) {
	vector<Point> Ret1, Ret2;
	double d = ABS(A2.c - A1.c);
	double r = A1.r;
	double Theta = atan2((A2.c - A1.c).py, (A2.c - A1.c).px);
	Ret1.push_back(A1.c + Polar(r, Theta + PI / 2.0));
	Ret1.push_back(A1.c + Polar(r, Theta - PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta + PI / 2.0));
	Ret2.push_back(A2.c + Polar(r, Theta - PI / 2.0));
	
	// Latter Half
	Point Mid = (A1.c + A2.c) * 0.5;
	double Theta2 = asin(2.0 * r / d);
	double dt = sqrt(0.25 * d * d - r * r);
	Ret1.push_back(Mid + Polar(dt, PI + Theta + Theta2));
	Ret1.push_back(Mid + Polar(dt, PI + Theta - Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta + Theta2));
	Ret2.push_back(Mid + Polar(dt, Theta - Theta2));
	return make_pair(Ret1, Ret2);
}

// Dot
double dot(Point A1, Point A2) {
	return A1.px * A2.px + A1.py * A2.py;
}

// Cross
double crs(Point A1, Point A2) {
	return A1.px * A2.py - A1.py * A2.px;
}

// Distance between segment A1A2 and Point A3
double DistSeg(Point A1, Point A2, Point A3) {
	if (dot(A2 - A1, A3 - A1) < 0.0) return ABS(A3 - A1);
	if (dot(A1 - A2, A3 - A2) < 0.0) return ABS(A3 - A2);
	double val = abs(crs(A2 - A1, A3 - A1));
	return val / ABS(A2 - A1);
}

int N; Point Start, Goal;
Circle Pole[19];
vector<pair<Point, int>> Cand;
double dist[1009][1009];

// Check if P1->P2 is valid for "straight move"
bool Passable(Point P1, Point P2) {
	for (int i = 1; i <= N; i++) {
		double dst = DistSeg(P1, P2, Pole[i].c);
		if (dst <= Pole[i].r - 1e-4) return false;
	}
	return true;
}

// Distance between angle1 and angle2
double DistAngle(double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	return 100.0 * (angle2 - angle1);
}

// Is it passable from angle1 to angle2 in circle idx?
bool PassCircle(int idx, double angle1, double angle2) {
	while (angle1 > angle2) angle2 += 2.0 * PI;
	Point P1 = Pole[idx].c + Polar(100.0, angle1);
	Point P2 = Pole[idx].c + Polar(100.0, angle2);
	for (int i = 1; i <= N; i++) {
		if (ABS(P1 - Pole[i].c) < 100.0 - 1.0e-4) return false;
		if (ABS(P2 - Pole[i].c) < 100.0 - 1.0e-4) return false;
	}
	for (int i = 1; i <= N; i++) {
		Point Diff = Pole[i].c - Pole[idx].c; if (ABS(Diff) > 200.0 - 1.0e-4) continue;
		double angle3 = atan2(Diff.py, Diff.px);
		while (angle1 > angle3) angle3 += 2.0 * PI;
		if (angle3 <= angle2) return false;
	}
	return true;
}

int main() {
	// Input
	cin >> N >> Goal.px >> Goal.py;
	for (int i = 1; i <= N; i++) cin >> Pole[i].c.px >> Pole[i].c.py;
	Start.px = 0.0;
	Start.py = 0.0;
	
	// Add to Candidate
	Cand.push_back(make_pair(Start, -1));
	Cand.push_back(make_pair(Goal, -1));
	for (int i = 1; i <= N; i++) {
		vector<Point> P1 = Tangent_PC(Start, Pole[i]);
		for (Point j : P1) Cand.push_back(make_pair(j, i));
		vector<Point> P2 = Tangent_PC(Goal, Pole[i]);
		for (Point j : P2) Cand.push_back(make_pair(j, i));
	}
	for (int i = 1; i <= N; i++) {
		for (int j = i + 1; j <= N; j++) {
			pair<vector<Point>, vector<Point>> P1 = Tangent_CC(Pole[i], Pole[j]);
			for (Point k : P1.first) Cand.push_back(make_pair(k, i));
			for (Point k : P1.second) Cand.push_back(make_pair(k, j));
		}
	}
	
	// Calculate Distance
	for (int i = 0; i < (int)Cand.size(); i++) {
		for (int j = 0; j < (int)Cand.size(); j++) {
			dist[i][j] = 1e9;
			if (Passable(Cand[i].first, Cand[j].first) == true) {
				double dst = ABS(Cand[i].first - Cand[j].first);
				dist[i][j] = min(dist[i][j], dst);
			}
			if (Cand[i].second == Cand[j].second && i != j && Cand[i].second != -1) {
				Point BASE = Pole[Cand[i].second].c;
				double angle1 = atan2((Cand[i].first - BASE).py, (Cand[i].first - BASE).px);
				double angle2 = atan2((Cand[j].first - BASE).py, (Cand[j].first - BASE).px);
				bool ret1 = PassCircle(Cand[i].second, angle1, angle2); // Angle1 -> Angle2
				bool ret2 = PassCircle(Cand[i].second, angle2, angle1);
				if (ret1 == true) dist[i][j] = min(dist[i][j], DistAngle(angle1, angle2));
				if (ret2 == true) dist[i][j] = min(dist[i][j], DistAngle(angle2, angle1));
				/*if (dist[i][j] < 1.0) {
					printf("%d %d %.12lf %.12lf\n", i, j, angle1, angle2);
				}*/
			}
		}
		dist[i][i] = 0.0;
	}
	/*for (int i = 0; i < (int)Cand.size(); i++) {
		for (int j = 0; j < (int)Cand.size(); j++) {
			int val = min(999, (int)dist[i][j]);
			printf("% 4d", val);
		}
		printf("\n");
	}*/
	
	// Warshall-Floyd
	for (int k = 0; k < (int)Cand.size(); k++) {
		for (int i = 0; i < (int)Cand.size(); i++) {
			for (int j = 0; j < (int)Cand.size(); j++) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
		}
	}
	
	// Output
	if (dist[0][1] > 1e8) printf("0.0\n");
	else printf("%.12lf\n", dist[0][1]);
	return 0;
}
accuracy: 0.04
time_ms: 10
memory_kb: 5728
final_rank: 20

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}

//円と直線の交点
//やっぱり交点が無かったらnullを返される
//交点は大体いつも2つあるのでvector
vector<Point> is_lc(Circle c, Line l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d > c.r + eps)return res;
	ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d);
	Point nor = (l.a - l.b) / abs(l.a - l.b);
	res.push_back(proj(l, c.p) + len * nor);
	if(len>eps)res.push_back(proj(l, c.p) - len * nor);
	return res;
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l))return res;
	Point v1 = v * Point{ l / d, c.r / d };
	Point v2 = v * Point{l / d, -c.r / d};
	res.push_back(Line{ p, p + v1 });
	//if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

vector<Line> tangent_cc(Circle c1, Circle c2) {
	vector<Line> res;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		res = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nres = tangent_cp(c1, out);
		res.insert(res.end(), nres.begin(), nres.end());
	}
	else {
		Point v = c2.p - c1.p; v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		res.push_back(Line{ q1,q1 + v });
		res.push_back(Line{ q2,q2 + v });
	}
	return res;
}
vector<Point> tangent_point(Circle c, Point p) {
	Point vd = p-c.p;
	ld d = abs(vd);
	vd *= 100 / (abs(vd));
	ld x = sqrt(d * d - 100 * 100);
	vector<Point> res;
	res.push_back(c.p+vd*Point{100 / d, x / d});
	res.push_back(c.p+vd*Point{100 / d,-x / d });
	return res;
}

struct edge {
	int to; ld cost;
};
ld trans(ld len) {
	if (len < eps) {
		return len;
	}
	ld t = asin(len / 200.0); t *= 2;
	//cout << len << " " << 100 * t << "\n";
	return 100 * t;
}
void solve() {
	int n, gx, gy; cin >> n >> gx >> gy;
	Point ps = { (ld)0,(ld)0 };
	Point pg = { (ld)gx,(ld)gy };
	vector<int> cx(n), cy(n);
	rep(i, n)cin >> cx[i] >> cy[i];
	vector<Point> cp(n);
	rep(i, n)cp[i] = { (ld)cx[i],(ld)cy[i] };
	vector<Point> vp;
	vector<vector<edge>> G(2);
	vp.push_back(ps);
	vp.push_back(pg);
	vector<Circle> c(n);
	rep(i, n) {
		c[i] = { {(ld)cx[i],(ld)cy[i]},100 };
	}
	vector<Line> banl;
	rep(i, n)Rep(j, i + 1, n) {
		Point pl = { (ld)cx[i],(ld)cy[i] };
		Point pr = { (ld)cx[j],(ld)cy[j] };
		//cout << abs(pl - pr) << "\n";
		if (abs(pl - pr) < 200) {
			//cout << i << " " << j << "\n";
			banl.push_back({ pl,pr });
		}
	}
	rep(i, n) {
		int ad = vp.size();
		vector<Point> cur;

		Point nw = { (ld)cx[i],(ld)cy[i] };
		Point dd = { 100,0 };
		rep(d, 4) {
			cur.push_back(nw + dd);
			dd *= Point{0, 1};
		}

		auto v = tangent_point(c[i], ps);
		for (Point p : v)cur.push_back(p);
		v = tangent_point(c[i], pg);
		for (Point p : v)cur.push_back(p);
		rep(j, n)if (i != j) {
			vector<Line> vl = tangent_cc(c[i], c[j]);
			for (Line l : vl) {
				auto vp = is_lc(c[i], l);
				for (Point p : vp)cur.push_back(p);
			}
			/*Point dp = cp[j] - cp[i];
			dp *= 100 / abs(dp);
			dp *= {0, 1};
			cur.push_back(nw + dp);
			cur.push_back(nw - dp);*/
		}
		{
			vector<Point> ncur;
			for (Point p : cur) {
				bool valid = true;
				rep(j, n) {
					if (abs(cp[j] - p) < 100 - eps)valid = false;
				}
				if (valid)ncur.push_back(p);
			}
			swap(cur, ncur);
		}
		for (Point p : cur) {
			vp.push_back(p);
			G.push_back({});
		}

		/*rep(k, cur.size()) {
			cout << abs(cur[k] - cp[i]) << "\n";
		}*/

		rep(j, cur.size())Rep(k, j + 1, cur.size()) {
			//if (abs(cur[j] - cur[k]) > 150)continue;
			if (abs(cur[j] - cur[k]) < eps) {
				G[ad + j].push_back({ ad+k,0 });
				G[ad + k].push_back({ ad+j,0 });
				continue;
			}
			Line z = { cur[j],cur[k] };
			bool valid = true;
			for (Line l : banl) {
				if (isis_ss(z, l))valid = false;
			}
			if (valid) {
				ld cost = trans(abs(cur[j] - cur[k]));
				G[ad + j].push_back({ ad + k,cost });
				G[ad + k].push_back({ ad + j,cost });
			}
		}
	}
	rep(i, vp.size())Rep(j, i + 1, vp.size()) {
		if (abs(vp[i] - vp[j]) < eps) {
			G[i].push_back({ j,0 });
			G[j].push_back({ i,0 });
			continue;
		}
		bool valid = true;
		Line l = { vp[i],vp[j] };
		rep(k, n) {
			//dame
			//if (abs(vp[i] - cp[k]) < eps)continue;
			//if (abs(vp[j] - cp[k]) < eps)continue;
			ld dist = dist_sp(l, cp[k]);
			if (dist < 100-eps)valid = false;
		}
		if (valid) {
			ld cost = abs(vp[i] - vp[j]);
			G[i].push_back({ j,cost });
			G[j].push_back({ i,cost });
		}
	}
	/*rep(i, vp.size())for (edge e : G[i]) {
		cout << vp[i] << " " << vp[e.to] << " " << e.cost << "\n";
	}*/
	vector<ld> dist(vp.size(),INF);
	dist[0] = 0;
	using speP = pair<ld, int>;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,0 });
	vector<int> pre(vp.size());
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (dist[id] < p.first)continue;
		for (edge e : G[id]) {
			ld nd = p.first + e.cost;
			if (nd < dist[e.to]) {
				dist[e.to] = nd;
				q.push({ nd,e.to });
				pre[e.to] = id;
			}
		}
	}
	ld ans = dist[1];
	if (ans == INF)ans = 0;
	cout << ans << "\n";

	int cur = 1;
	while (cur > 0) {
		//cout << vp[cur] << "\n";
		cur = pre[cur];
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 6156
final_rank: 14

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-4;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	//誤差がisis_lpに比べて大きいので、できるだけisis_lpを使う
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
//bool isis_ss(Line s, Line t) {
//	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
//}
//線分と線分の交差判定2
bool isis_ss(Line s, Line t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}

//円と直線の交点
//やっぱり交点が無かったらnullを返される
//交点は大体いつも2つあるのでvector
vector<Point> is_lc(Circle c, Line l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d > c.r + eps)return res;
	ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d);
	Point nor = (l.a - l.b) / abs(l.a - l.b);
	res.push_back(proj(l, c.p) + len * nor);
	if(len>eps)res.push_back(proj(l, c.p) - len * nor);
	return res;
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l))return res;
	Point v1 = v * Point{ l / d, c.r / d };
	Point v2 = v * Point{l / d, -c.r / d};
	res.push_back(Line{ p, p + v1 });
	//if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

vector<Line> tangent_cc(Circle c1, Circle c2) {
	vector<Line> res;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		res = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nres = tangent_cp(c1, out);
		res.insert(res.end(), nres.begin(), nres.end());
	}
	else {
		Point v = c2.p - c1.p; v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		res.push_back(Line{ q1,q1 + v });
		res.push_back(Line{ q2,q2 + v });
	}
	return res;
}
vector<Point> tangent_point(Circle c, Point p) {
	Point vd = p-c.p;
	ld d = abs(vd);
	vd *= 100 / (abs(vd));
	ld x = sqrt(d * d - 100 * 100);
	vector<Point> res;
	res.push_back(c.p+vd*Point{100 / d, x / d});
	res.push_back(c.p+vd*Point{100 / d,-x / d });
	return res;
}

struct edge {
	int to; ld cost;
};
ld trans(ld len) {
	if (len < eps) {
		return len;
	}
	ld t = asin(len / 200.0); t *= 2;
	//cout << len << " " << 100 * t << "\n";
	return 100 * t;
}
void solve() {
	int n, gx, gy; cin >> n >> gx >> gy;
	Point ps = { (ld)0,(ld)0 };
	Point pg = { (ld)gx,(ld)gy };
	vector<int> cx(n), cy(n);
	rep(i, n)cin >> cx[i] >> cy[i];
	vector<Point> cp(n);
	rep(i, n)cp[i] = { (ld)cx[i],(ld)cy[i] };
	vector<Point> vp;
	vector<vector<edge>> G(2);
	vp.push_back(ps);
	vp.push_back(pg);
	vector<Circle> c(n);
	rep(i, n) {
		c[i] = { {(ld)cx[i],(ld)cy[i]},100 };
	}
	vector<Line> banl;
	rep(i, n)Rep(j, i + 1, n) {
		Point pl = { (ld)cx[i],(ld)cy[i] };
		Point pr = { (ld)cx[j],(ld)cy[j] };
		if (abs(pl - pr) < 200) {
			//cout << i << " " << j << "\n";
			banl.push_back({ pl,pr });
		}
	}
	rep(i, n) {
		int ad = vp.size();
		vector<Point> cur;

		Point nw = { (ld)cx[i],(ld)cy[i] };
		Point dd = { 100,0 };
		rep(d, 4) {
			cur.push_back(nw + dd);
			dd *= Point{0, 1};
		}

		auto v = tangent_point(c[i], ps);
		for (Point p : v)cur.push_back(p);
		v = tangent_point(c[i], pg);
		for (Point p : v)cur.push_back(p);
		rep(j, n)if (i != j) {
			vector<Line> vl = tangent_cc(c[i], c[j]);
			for (Line l : vl) {
				auto vp = is_lc(c[i], l);
				for (Point p : vp)cur.push_back(p);
			}
			/*Point dp = cp[j] - cp[i];
			dp *= 100 / abs(dp);
			dp *= {0, 1};
			cur.push_back(nw + dp);
			cur.push_back(nw - dp);*/
		}

		for (Point p : cur) {
			vp.push_back(p);
			G.push_back({});
		}

		/*rep(k, cur.size()) {
			cout << abs(cur[k] - cp[i]) << "\n";
		}*/

		rep(j, cur.size())Rep(k, j + 1, cur.size()) {
			if (abs(cur[j] - cur[k]) < eps) {
				G[ad + j].push_back({ ad+k,0 });
				G[ad + k].push_back({ ad+j,0 });
				continue;
			}
			Line z = { cur[j],cur[k] };
			bool valid = true;
			for (Line l : banl) {
				if (isis_ss(z, l))valid = false;
			}
			if (valid) {
				ld cost = trans(abs(cur[j] - cur[k]));
				G[ad + j].push_back({ ad + k,cost });
				G[ad + k].push_back({ ad + j,cost });
			}
		}
	}
	rep(i, vp.size())Rep(j, i + 1, vp.size()) {
		if (abs(vp[i] - vp[j]) < eps) {
			G[i].push_back({ j,0 });
			G[j].push_back({ i,0 });
			continue;
		}
		bool valid = true;
		Line l = { vp[i],vp[j] };
		rep(k, n) {
			if (abs(vp[i] - cp[k]) < eps)continue;
			if (abs(vp[j] - cp[k]) < eps)continue;
			ld dist = dist_sp(l, { (ld)cx[k],(ld)cy[k] });
			if (dist < 100 - (1e-4))valid = false;
		}
		if (valid) {
			ld cost = abs(vp[i] - vp[j]);
			G[i].push_back({ j,cost });
			G[j].push_back({ i,cost });
		}
	}
	/*rep(i, vp.size())for (edge e : G[i]) {
		cout << vp[i] << " " << vp[e.to] << " " << e.cost << "\n";
	}*/
	vector<ld> dist(vp.size(),INF);
	dist[0] = 0;
	using speP = pair<ld, int>;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,0 });
	vector<int> pre(vp.size());
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (dist[id] < p.first)continue;
		for (edge e : G[id]) {
			ld nd = p.first + e.cost;
			if (nd < dist[e.to]) {
				dist[e.to] = nd;
				q.push({ nd,e.to });
				pre[e.to] = id;
			}
		}
	}
	ld ans = dist[1];
	if (ans == INF)ans = 0;
	cout << ans << "\n";

	int cur = 1;
	while (cur > 0) {
		//cout << vp[cur] << "\n";
		cur = pre[cur];
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 0.1
time_ms: 90
memory_kb: 4660
final_rank: 17

code_snippet: #define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
typedef pair<ld, int> pdi;
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

// NOTE: Internal tangents will have NaN coordinates if the circles intersect.
//       But in this program it's not necessary to manually handle these cases.
struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) + EPS < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * M_PI;
    return fabs(angle * radius);
  }

  bool tangents_same_direction(Segment in_tan, Segment out_tan) {
    return same_direction(in_tan.p, in_tan.q, out_tan.p, out_tan.q);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) > radius + c.radius) return false;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      Segment tan = incoming_tan;
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    }

    return !same_direction(incoming_tan.p, incoming_tan.q, center, c.center) &&
           !same_direction(outgoing_tan.q, outgoing_tan.p, center, c.center);
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return same_direction(in.p, in.q, center, out.p);
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }

  bool same_direction(Point a, Point b, Point c, Point d) {
    int sgn1 = sgn(a.to(b) ^ b.to(c));
    int sgn2 = sgn(b.to(c) ^ c.to(d));
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }
};

struct Node {
  Point point;
  int id;
  vector<pdi> edges;
  Node(Point p, int id) : point(p), id(id) {}
  Node() {}
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_valid(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool arc_intersect_any_circle(int pole_idx, Segment& in_tan, Segment& out_tan) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return true;
  }
  return false;
}

vector<Node> graph;
unordered_map<int, vector<int>> points_in_pole;
int node_id;

int add_node(Point p, int pole_idx) {
  int new_node_id = node_id;
  graph.push_back(Node(p, node_id++));
  if (pole_idx > -1) points_in_pole[pole_idx].push_back(new_node_id);
  return new_node_id;
}

inline int add_node(Point p) { return add_node(p, -1); }

void solve() {
  node_id = 0;
  graph.clear();
  Segment direct_robot_goal(robot, goal);

  if (movement_valid(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) points_in_pole[i] = vector<int>();

  const int ROBOT_NODE_ID = add_node(robot);
  const int GOAL_NODE_ID = add_node(goal);

  for (int i = 0; i < (int)poles.size(); i++) {
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_valid(tangent)) {
        int n = add_node(tangent.q, i);
        graph[ROBOT_NODE_ID].edges.push_back({tangent.length(), n});
      }

    for (Segment& tangent : poles[i].tangents_from_point(goal))
      if (movement_valid(tangent)) {
        int n = add_node(tangent.q, i);
        graph[n].edges.push_back({tangent.length(), GOAL_NODE_ID});
      }

    for (int j = i + 1; j < (int)poles.size(); j++)
      for (Segment& tangent : poles[i].tangents_to(poles[j]))
        if (movement_valid(tangent)) {
          int n1 = add_node(tangent.p, i);
          int n2 = add_node(tangent.q, j);
          graph[n1].edges.push_back({tangent.length(), n2});
          graph[n2].edges.push_back({tangent.length(), n1});
        }
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    for (int j = 0; j < (int)points_in_pole[i].size(); j++)
      for (int k = j + 1; k < (int)points_in_pole[i].size(); k++) {
        int p1 = points_in_pole[i][j];
        int p2 = points_in_pole[i][k];

        Point center = poles[i].center;
        Point in_pt = graph[p1].point;
        Point out_pt = graph[p2].point;

        array<pair<Segment, Segment>, 4> tangent_combinations{
            make_pair(Segment(in_pt + center.to(in_pt).rot_ccw(), in_pt),
                      Segment(out_pt, out_pt + center.to(out_pt).rot_cw())),
            make_pair(Segment(in_pt + center.to(in_pt).rot_cw(), in_pt),
                      Segment(out_pt, out_pt + center.to(out_pt).rot_ccw()))};

        for (pair<Segment, Segment> combination : tangent_combinations) {
          auto [in_tan, out_tan] = combination;
          if (!arc_intersect_any_circle(i, in_tan, out_tan)) {
            ld arc = poles[i].arc(in_tan, out_tan);
            graph[p1].edges.push_back({arc, p2});
            graph[p2].edges.push_back({arc, p1});
          }
        }
      }
  }

  vector<ld> dist(graph.size(), DBL_MAX);

  priority_queue<pdi, vector<pdi>, greater<pdi>> q;

  q.push({0, ROBOT_NODE_ID});
  dist[ROBOT_NODE_ID] = 0;

  while (!q.empty()) {
    auto [_, u] = q.top();
    q.pop();
    for (auto& [weight, v] : graph[u].edges) {
      ld alt = dist[u] + weight;
      if (alt < dist[v]) {
        dist[v] = alt;
        q.push({alt, v});
      }
    }
  }

  printf("%.8Lf\n", dist[GOAL_NODE_ID] == DBL_MAX ? 0.0 : dist[GOAL_NODE_ID]);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 20
memory_kb: 4828
final_rank: 10

code_snippet: #define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
typedef pair<ld, int> pdi;
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

// NOTE: Internal tangents will have NaN coordinates if the circles intersect.
//       But in this program it's not necessary to manually handle these cases.
struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) + EPS < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * M_PI;
    return fabs(angle * radius);
  }

  bool tangents_same_direction(Segment in_tan, Segment out_tan) {
    return same_direction(in_tan.p, in_tan.q, out_tan.p, out_tan.q);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) > radius + c.radius) return false;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      Segment tan = incoming_tan;
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    }

    return !same_direction(incoming_tan.p, incoming_tan.q, center, c.center) &&
           !same_direction(outgoing_tan.q, outgoing_tan.p, center, c.center);
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return same_direction(in.p, in.q, center, out.p);
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }

  bool same_direction(Point a, Point b, Point c, Point d) {
    int sgn1 = sgn(a.to(b) ^ b.to(c));
    int sgn2 = sgn(b.to(c) ^ c.to(d));
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }
};

struct Node {
  Point point;
  int id;
  vector<pdi> edges;
  Node(Point p, int id) : point(p), id(id) {}
  Node() {}
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_valid(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool arc_intersect_any_circle(int pole_idx, Segment& in_tan, Segment& out_tan) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return true;
  }
  return false;
}

vector<Node> graph;
unordered_map<int, vector<int>> points_in_pole;
int node_id;

int add_node(Point p, int pole_idx) {
  int new_node_id = node_id;
  graph.push_back(Node(p, node_id++));
  if (pole_idx > -1) points_in_pole[pole_idx].push_back(new_node_id);
  return new_node_id;
}

inline int add_node(Point p) { return add_node(p, -1); }

void solve() {
  node_id = 0;
  graph.clear();
  Segment direct_robot_goal(robot, goal);

  if (movement_valid(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) points_in_pole[i] = vector<int>();

  const int ROBOT_NODE_ID = add_node(robot);
  const int GOAL_NODE_ID = add_node(goal);

  for (int i = 0; i < (int)poles.size(); i++) {
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_valid(tangent)) {
        int n = add_node(tangent.q, i);
        graph[ROBOT_NODE_ID].edges.push_back(make_pair(tangent.length(), n));
      }

    for (Segment& tangent : poles[i].tangents_from_point(goal))
      if (movement_valid(tangent)) {
        int n = add_node(tangent.q, i);
        graph[n].edges.push_back(make_pair(tangent.length(), GOAL_NODE_ID));
      }

    for (int j = i + 1; j < (int)poles.size(); j++)
      for (Segment& tangent : poles[i].tangents_to(poles[j]))
        if (movement_valid(tangent)) {
          int n1 = add_node(tangent.p, i);
          int n2 = add_node(tangent.q, j);
          graph[n1].edges.push_back(make_pair(tangent.length(), n2));
          graph[n2].edges.push_back(make_pair(tangent.length(), n1));
        }
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    for (int j = 0; j < (int)points_in_pole[i].size(); j++)
      for (int k = j + 1; k < (int)points_in_pole[i].size(); k++) {
        int p1 = points_in_pole[i][j];
        int p2 = points_in_pole[i][k];

        Point center = poles[i].center;
        Point in_pt = graph[p1].point;
        Point out_pt = graph[p2].point;

        array<pair<Segment, Segment>, 4> tangent_combinations{
            make_pair(Segment(in_pt + center.to(in_pt).rot_ccw(), in_pt),
                      Segment(out_pt, out_pt + center.to(out_pt).rot_cw())),
            make_pair(Segment(in_pt + center.to(in_pt).rot_cw(), in_pt),
                      Segment(out_pt, out_pt + center.to(out_pt).rot_ccw()))};

        for (pair<Segment, Segment> combination : tangent_combinations) {
          auto [in_tan, out_tan] = combination;
          if (!arc_intersect_any_circle(i, in_tan, out_tan)) {
            ld arc = poles[i].arc(in_tan, out_tan);
            graph[p1].edges.push_back(make_pair(arc, p2));
            graph[p2].edges.push_back(make_pair(arc, p1));
          }
        }
      }
  }

  vector<ld> dist(graph.size(), DBL_MAX);

  priority_queue<pdi, vector<pdi>, greater<pdi>> q;

  q.push(make_pair(0, ROBOT_NODE_ID));
  dist[ROBOT_NODE_ID] = 0;

  while (!q.empty()) {
    pdi u = q.top();
    q.pop();
    for (pdi v : graph[u.second].edges) {
      Node neighbor = graph[v.second];
      ld alt = dist[u.second] + v.first;
      if (alt < dist[v.second]) {
        dist[v.second] = alt;
        q.push(make_pair(alt, v.second));
      }
    }
  }

  printf("%.8Lf\n", dist[GOAL_NODE_ID] == DBL_MAX ? 0.0 : dist[GOAL_NODE_ID]);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 20
memory_kb: 4736
final_rank: 1

code_snippet: #define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

// NOTE: Internal tangents will have NaN coordinates if the circles intersect.
//       But in this program it's not necessary to manually handle these cases.
struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) + EPS < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * M_PI;
    return fabs(angle * radius);
  }

  bool tangents_same_direction(Segment in_tan, Segment out_tan) {
    return same_direction(in_tan.p, in_tan.q, out_tan.p, out_tan.q);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) > radius + c.radius) return false;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      Segment tan = incoming_tan;
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    }

    return !same_direction(incoming_tan.p, incoming_tan.q, center, c.center) &&
           !same_direction(outgoing_tan.q, outgoing_tan.p, center, c.center);
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return same_direction(in.p, in.q, center, out.p);
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }

  bool same_direction(Point a, Point b, Point c, Point d) {
    int sgn1 = sgn(a.to(b) ^ b.to(c));
    int sgn2 = sgn(b.to(c) ^ c.to(d));
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_valid(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool tangent_movement_valid(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!poles[pole_idx].tangents_same_direction(in_tan, out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return movement_valid(out_tan);
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : curr_pole.tangents_from_point(goal)) {
    tangent = tangent.invert();
    if (!tangent_movement_valid(pole_idx, from, tangent)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    if (!visited[i])
      for (Segment& tangent : curr_pole.tangents_to(poles[i]))
        if (tangent_movement_valid(pole_idx, from, tangent)) {
          ld arc = curr_pole.arc(from, tangent);
          bitset<8> v = visited;
          traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
        }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_valid(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_valid(tangent))
        traverse(i, tangent, bitset<8>(1 << i), tangent.length());

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4028
final_rank: 6

code_snippet: #define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) + EPS < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * M_PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) > radius + c.radius) return false;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      Segment tan = incoming_tan;
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    }

    Segment to_circle = Segment(center, c.center);
    return !incoming_tan.same_direction(to_circle) &&
           !outgoing_tan.invert().same_direction(to_circle);
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return in.same_direction(Segment(center, out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_valid(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool tangent_movement_valid(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return movement_valid(out_tan);
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : curr_pole.tangents_from_point(goal)) {
    tangent = tangent.invert();
    if (!tangent_movement_valid(pole_idx, from, tangent)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    if (!visited[i])
      for (Segment& tangent : curr_pole.tangents_to(poles[i]))
        if (tangent_movement_valid(pole_idx, from, tangent)) {
          ld arc = curr_pole.arc(from, tangent);
          bitset<8> v = visited;
          traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
        }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_valid(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_valid(tangent))
        traverse(i, tangent, bitset<8>(1 << i), tangent.length());

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4028
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) + EPS < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      /*bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;*/
      Segment to_circle = Segment(center, c.center);
      bool intersect1 = !incoming_tan.same_direction(to_circle);
      bool intersect2 = !outgoing_tan.invert().same_direction(to_circle);
      return intersect1 || intersect2;
    } else {
      Segment to_circle = Segment(center, c.center);
      bool intersect1 = !incoming_tan.same_direction(to_circle);
      bool intersect2 = !outgoing_tan.invert().same_direction(to_circle);
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return in.same_direction(Segment(center, out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_possible(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : curr_pole.tangents_from_point(goal)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_possible(tangent))
        traverse(i, tangent, bitset<8>(1 << i), tangent.length());

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 550
memory_kb: 4032
final_rank: 15

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist_point(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) {
    return s.dist_point(center) + EPS < radius;
  }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

  array<Segment, 2> tangents_from_point(Point p) {
    ld a = radius, b = p.dist(center);
    ld th = acos(a / b);
    ld d = atan2(p.y - center.y, p.x - center.x);
    ld d1 = d + th, d2 = d - th;
    return array<Segment, 2>{
        Segment(p, Point(center.x + a * cos(d1), center.y + a * sin(d1))),
        Segment(p, Point(center.x + a * cos(d2), center.y + a * sin(d2)))};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = c.tangents_from_point(mid);
    auto point_tans2 = tangents_from_point(mid);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

bool movement_possible(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : curr_pole.tangents_from_point(goal)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : poles[i].tangents_from_point(robot))
      if (movement_possible(tangent))
        traverse(i, tangent, bitset<8>(1 << i), tangent.length());

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4024
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846
const ld EPS = 1e-12;

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist_point(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) {
    return s.dist_point(center) + EPS < radius;
  }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s) {
  for (int i = 0; i < (int)poles.size(); i++)
    if (poles[i].intersect(s)) return false;
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent))
        traverse(i, tangent, bitset<8>(1 << i), tangent.length());

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 140
memory_kb: 4024
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist_point(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist_point(center) < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++)
    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1)) {
        bitset<8> visited;
        traverse(i, tangent, visited.set(i), tangent.length());
      }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4024
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist_point(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist_point(center) < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment& in_tan, Segment& out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment& from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1)) {
        bitset<8> visited;
        traverse(i, tangent, visited.set(i), tangent.length());
      }
  }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4028
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment in_tan, Segment out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment from, int visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if ((visited & (1 << i)) > 0) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      // b//  // itset<8> v = visited;
      traverse(i, tangent, visited | (1 << i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    // bitset<8> visited;

    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1))
        traverse(i, tangent, (1 << i), tangent.length());
  }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4024
final_rank: 3

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment in_tan, Segment out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    bitset<8> visited;

    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1))
        traverse(i, tangent, visited.set(i), tangent.length());
  }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    scanf("%Le %Le", &goal.x, &goal.y);

    while (N--) {
      Point p;
      scanf("%Le %Le", &p.x, &p.y);
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4028
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }

  ld dist(Point P) {
    Segment L = *this;
    if ((P - L.p) * L.to_vec() < 0)
      return P.dist(L.p);
    else if ((P - L.q) * L.to_vec() > 0)
      return P.dist(L.q);
    else
      return fabs(L.to_vec() ^ (P - L.p)) / L.to_vec().magnitude();
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  inline bool intersect(Segment s) { return s.dist(center) < radius; }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment in_tan, Segment out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    bitset<8> visited;

    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1))
        traverse(i, tangent, visited.set(i), tangent.length());
  }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    cin >> goal.x >> goal.y;

    while (N--) {
      Point p;
      cin >> p.x >> p.y;
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 130
memory_kb: 4020
final_rank: 2

code_snippet: #include <bits/stdc++.h>

using namespace std;
typedef long double ld;
#define PI 3.14159265358979323846

inline int sgn(int n) { return n < 0 ? -1 : n > 0; }

struct Point {
  ld x, y;
  Point(ld x, ld y) : x(x), y(y) {}
  Point() {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  inline ld operator^(const Point& p) const { return (x * p.y) - (y * p.x); }
  inline ld operator*(const Point& p) const { return (x * p.x) + (y * p.y); }
  inline bool operator==(const Point& p) const { return x == p.x && y == p.y; }
  Point to(const Point& p) const { return p - *this; }
  inline ld magnitude() { return sqrt((x * x) + (y * y)); }
  inline ld dist(const Point& p) { return to(p).magnitude(); }
  Point rot_ccw() { return Point(-y, x); }
  Point rot_cw() { return Point(y, -x); }
  Point normalize() { return Point(x / magnitude(), y / magnitude()); }
  Point scale(ld f) { return Point(x * f, y * f); }
};

struct Segment {
  Point p, q;
  Segment(Point p, Point q) : p(p), q(q) {}
  Segment() {}
  Segment invert() { return Segment(q, p); }
  Segment scale(ld f) { return Segment(p, p + p.to(q).scale(f)); }
  inline ld length() { return p.dist(q); }
  Point to_vec() { return p.to(q); }
  bool same_direction(Segment s) {
    int sgn1 = sgn(to_vec() ^ q.to(s.p));
    int sgn2 = sgn(q.to(s.p) ^ s.to_vec());
    return sgn1 == 0 || sgn2 == 0 || sgn1 == sgn2;
  }
};

struct Circle;
array<Segment, 2> point_circle_tangents(Point p, Circle c);

struct Circle {
  Point center;
  ld radius;
  Circle(Point c, ld r) : center(c), radius(r) {}

  bool intersect(Segment s) {
    ld left = 0L, right = 1L;
    while (fabs(left - right) > 0.01L) {
      ld third = (right - left) / 3L;
      ld third1 = left + third, third2 = right - third;
      if (s.scale(third1).q.dist(center) > s.scale(third2).q.dist(center))
        left = third1;
      else
        right = third2;
    }
    return s.scale(left).q.dist(center) < radius;
  }

  ld arc(Segment incoming_tan, Segment outgoing_tan) {
    Point a = center.to(incoming_tan.q);
    Point b = center.to(outgoing_tan.p);
    ld angle = acos(a * b / (a.magnitude() * b.magnitude()));
    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) angle -= 2 * PI;
    return fabs(angle * radius);
  }

  bool arc_intersects(Circle c, Segment incoming_tan, Segment outgoing_tan) {
    if (center.dist(c.center) >= radius + c.radius) return false;
    Segment tan = incoming_tan;

    if (tangents_reflex_angle(incoming_tan, outgoing_tan)) {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(outgoing_tan.p));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) ==
                        sgn(center.to(c.center) ^ center.to(incoming_tan.q));
      return intersect1 || intersect2;
    } else {
      bool intersect1 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      tan = outgoing_tan.invert();
      bool intersect2 = sgn(tan.to_vec() ^ tan.q.to(center)) !=
                        sgn(tan.q.to(center) ^ center.to(c.center));
      return intersect1 && intersect2;
    }
  }

  array<Segment, 4> tangents_to(Circle c) {
    return array<Segment, 4>{external_tangents(c)[0], external_tangents(c)[1],
                             internal_tangents(c)[0], internal_tangents(c)[1]};
  }

 private:
  bool tangents_reflex_angle(Segment in, Segment out) {
    return sgn(in.to_vec() ^ in.q.to(center)) ==
           sgn(in.q.to(center) ^ center.to(out.p));
  }

  array<Segment, 2> external_tangents(Circle c) {
    Point shift1 = center.to(c.center).normalize().rot_cw().scale(radius);
    Point shift2 = center.to(c.center).normalize().rot_ccw().scale(radius);
    return array<Segment, 2>{Segment(center + shift1, c.center + shift1),
                             Segment(center + shift2, c.center + shift2)};
  }

  array<Segment, 2> internal_tangents(Circle c) {
    Point mid = Segment(center, c.center).scale(0.5L).q;
    auto point_tans1 = point_circle_tangents(mid, c);
    auto point_tans2 = point_circle_tangents(mid, *this);
    return array<Segment, 2>{Segment(point_tans2[0].q, point_tans1[0].q),
                             Segment(point_tans2[1].q, point_tans1[1].q)};
  }
};

vector<Circle> poles;
Point robot(0, 0), goal;
ld min_dist;

array<Segment, 2> point_circle_tangents(Point p, Circle c) {
  ld a = c.radius, b = p.dist(c.center);
  ld th = acos(a / b);
  ld d = atan2(p.y - c.center.y, p.x - c.center.x);
  ld d1 = d + th, d2 = d - th;
  return array<Segment, 2>{
      Segment(p, Point(c.center.x + a * cos(d1), c.center.y + a * sin(d1))),
      Segment(p, Point(c.center.x + a * cos(d2), c.center.y + a * sin(d2)))};
}

bool movement_possible(Segment& s, int ignore_pole_idx1, int ignore_pole_idx2) {
  for (int i = 0; i < (int)poles.size(); i++) {
    if (i == ignore_pole_idx1 || i == ignore_pole_idx2) continue;
    if (poles[i].intersect(s)) return false;
  }
  return true;
}

bool valid_tangent_traversal(int pole_idx, Segment in_tan, Segment out_tan) {
  if (!in_tan.same_direction(out_tan)) return false;
  for (int i = 0; i < (int)poles.size(); i++) {
    if (pole_idx == i) continue;
    if (poles[pole_idx].arc_intersects(poles[i], in_tan, out_tan)) return false;
  }
  return true;
}

void traverse(int pole_idx, Segment from, bitset<8> visited, ld dist) {
  if (dist > min_dist) return;
  Circle& curr_pole = poles[pole_idx];

  for (Segment& tangent : point_circle_tangents(goal, curr_pole)) {
    tangent = tangent.invert();
    if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
    if (!movement_possible(tangent, pole_idx, -1)) continue;
    min_dist =
        min(min_dist, dist + tangent.length() + curr_pole.arc(from, tangent));
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    if (visited[i]) continue;

    for (Segment& tangent : curr_pole.tangents_to(poles[i])) {
      if (!valid_tangent_traversal(pole_idx, from, tangent)) continue;
      if (!movement_possible(tangent, pole_idx, i)) continue;

      ld arc = curr_pole.arc(from, tangent);
      bitset<8> v = visited;
      traverse(i, tangent, v.set(i), dist + tangent.length() + arc);
    }
  }
}

void solve() {
  Segment direct_robot_goal(robot, goal);

  if (movement_possible(direct_robot_goal, -1, -1)) {
    printf("%.5Lf\n", direct_robot_goal.length());
    return;
  }

  for (int i = 0; i < (int)poles.size(); i++) {
    bitset<8> visited;

    for (Segment& tangent : point_circle_tangents(robot, poles[i]))
      if (movement_possible(tangent, i, -1))
        traverse(i, tangent, visited.set(i), tangent.length());
  }

  printf("%.8Lf\n", min_dist == DBL_MAX ? 0.0 : min_dist);
}

int main() {
  int N;

  while (scanf("%d", &N) == 1) {
    min_dist = DBL_MAX;
    poles.clear();
    cin >> goal.x >> goal.y;

    while (N--) {
      Point p;
      cin >> p.x >> p.y;
      poles.push_back(Circle(p, 100L));
    }
    solve();
  }
}
accuracy: 1
time_ms: 410
memory_kb: 4028
final_rank: 13