Problem:
Lake Survery
The Onogawa Expedition is planning to conduct a survey of the Aizu nature reserve. The expedition planner wants to take the shortest possible route from the start to end point of the survey, while the expedition has to go around the coast of the Lake of Onogawa en route. The expedition walks along the coast of the lake, but can not wade across the lake.
Based on the base information including the start and end point of the survey and the area of Lake Onogawa as convex polygon data, make a program to find the shortest possible route for the expedition and calculate its distance. Note that the expedition can move along the polygonal lines passing through the nodes, but never enter within the area enclosed by the polygon.
Input
The input is given in the following format.
x_s
y_s
x_g
y_g
N
x_1
y_1
x_2
y_2
:
x_N
y_N
The first line provides the start point of the survey
x_s,y_s
(0≤
x_s,y_s
≤10
4
), and the second line provides the end point
x_g,y_g
(0 ≤
x_g,y_g
≤ 10
4
) all in integers. The third line provides the number of apexes
N
(3 ≤
N
≤ 100) of the polygon that represents the lake, and each of the subsequent
N
lines provides the coordinate of the
i
-th apex
x_i,y_i
(0 ≤
x_i,y_i
≤ 10
4
) in counter-clockwise order. These data satisfy the following criteria:
Start and end points of the expedition are not within the area enclosed by the polygon nor on boundaries.
Start and end points of the expedition are not identical, i.e.,
x_s ≠ x_g
or
y_s ≠ y_g
.
No duplicate coordinates are given, i.e., if
i ≠ j
then
x_i ≠ x_r
or
y_i ≠ y_j
.
The area enclosed by the polygon has a positive value.
Any three coordinates that define an area are not aligned on a line.
Output
Output the distance of the shortest possible expedition route. Any number of decimal places can be selected as long as the error does not exceed ± 10
-3
.
Sample Input 1
0 0
4 0
4
1 1
2 1
3 3
1 2
Sample Output 1
4.472136
Sample Input 2
4 4
0 0
4
1 1
3 1
3 3
1 3
Sample Output 2
6.32455

Submitted solutions:

code_snippet: #include <cmath>
#include <vector>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
class point2d {
public:
	double x, y;
	point2d() : x(0), y(0) {};
	point2d(double x_, double y_) : x(x_), y(y_) {};
	bool operator==(const point2d& p) const { return x == p.x && y == p.y; }
	bool operator!=(const point2d& p) const { return x != p.x || y != p.y; }
	point2d& operator+=(const point2d& p) { x += p.x; y += p.y; return *this; }
	point2d& operator-=(const point2d& p) { x -= p.x; y -= p.y; return *this; }
	point2d& operator*=(const double v) { x *= v; y *= v; return *this; }
	point2d operator+(const point2d& p) const { return point2d(*this) += p; }
	point2d operator-(const point2d& p) const { return point2d(*this) -= p; }
	point2d operator*(const double v) const { return point2d(*this) *= v; }
	double norm() const { return x * x + y * y; }
	double abs() const { return std::sqrt(x * x + y * y); }
	double dot(const point2d& p) const { return x * p.x + y * p.y; }
	double cross(const point2d& p) const { return x * p.y - y * p.x; }
	int ccw(const point2d& p1, const point2d& p2) const {
		point2d pr1 = p1 - point2d(*this);
		point2d pr2 = p2 - point2d(*this);
		if (pr1.cross(pr2) != 0) return pr1.cross(pr2) > 0 ? 1 : -1;
		if (pr1.dot(pr2) < 0) return 2;
		return pr1.norm() < pr2.norm() ? -2 : 0;
	}
};
class segment2d {
public:
	point2d p1, p2;
	segment2d() : p1(), p2() {};
	segment2d(const point2d& p1_, const point2d& p2_) : p1(p1_), p2(p2_) {};
	double norm() const { return (p1 - p2).norm(); }
	double abs() const { return (p1 - p2).abs(); }
};
bool intersect(const segment2d& s1, const segment2d& s2) {
	if (s1.p1 == s2.p1 || s1.p1 == s2.p2 || s1.p2 == s2.p1 || s1.p2 == s2.p2) return false; // EXCEPTION !!!
	return s1.p1.ccw(s1.p2, s2.p1) * s1.p1.ccw(s1.p2, s2.p2) <= 0 && s2.p1.ccw(s2.p2, s1.p1) * s2.p1.ccw(s2.p2, s1.p2) <= 0;
}
point2d intersect_point(const segment2d &s1, const segment2d &s2) {
	point2d base = s2.p2 - s2.p1;
	double d1 = std::abs(base.cross(s1.p1 - s2.p1));
	double d2 = std::abs(base.cross(s1.p2 - s2.p1));
	return s1.p1 + (s1.p2 - s1.p1) * (d1 / (d1 + d2));
}
bool contain(const std::vector<point2d>& v, const point2d& p) {
	int ans = -1;
	for (int i = 0; i < v.size(); ++i) {
		point2d p1 = v[i] - p;
		point2d p2 = v[(i + 1) % v.size()] - p;
		if (p1.x > p2.x) std::swap(p1, p2);
		if (p1.x <= 0 && 0 < p2.x && p1.cross(p2) < 0) ans *= -1;
	}
	return (ans == 1);
}
int main() {
	int n;
	vector<point2d> v(2);
	cin >> v[0].x >> v[0].y >> v[1].x >> v[1].y;
	cin >> n;
	v.resize(n + 2);
	for (int i = 2; i < n + 2; ++i) {
		cin >> v[i].x >> v[i].y;
	}
	// Shortest Path (Warshall-Floyd Algorithm)
	vector<vector<double> > d(n + 2, vector<double>(n + 2, 1.0e+99));
	for (int i = 0; i < n + 2; ++i) {
		d[i][i] = 0;
	}
	for (int i = 0; i < n + 2; ++i) {
		for (int j = 0; j < i; ++j) {
			// Going to vertex j from vertex i
			bool ok = true;
			for (int k = 0; k < v.size() - 2; ++k) {
				segment2d s(v[k + 2], v[(k + 1) % (v.size() - 2) + 2]);
				if (intersect(s, segment2d(v[i], v[j]))) {
					//cout << i << ' ' << j << ' ' << k << "-" << k + 1 << endl;
					ok = false;
				}
			}
			if (contain(vector<point2d>(v.begin() + 2, v.end()), (v[i] + v[j]) * 0.5)) {
				ok = false;
			}
			if (ok || (j >= 2 && i - j == 1) || (j == 2 && i == n + 1)) {
				//cout << i << ' ' << j << endl;
				d[i][j] = (v[i] - v[j]).abs();
				d[j][i] = (v[i] - v[j]).abs();
			}
		}
	}
	d[0][1] = 1.0e+99;
	d[1][0] = 1.0e+99;
	for (int i = 0; i < n + 2; ++i) {
		for (int j = 0; j < n + 2; ++j) {
			for (int k = 0; k < n + 2; ++k) {
				d[j][k] = min(d[j][k], d[j][i] + d[i][k]);
			}
		}
	}
	double ans = d[0][1];
	for (int i = 0; i < n; ++i) {
		point2d p1 = v[i + 2], p2 = v[(i + 1) % (v.size() - 2) + 2];
		point2d bs = p1 + (p2 - p1) * (v[1] - p1).dot(p2 - p1) * (1.0 / (p2 - p1).norm());
		point2d rfl = bs * 2 - v[1];
		point2d crp = intersect_point(segment2d(p1, p2), segment2d(v[0], rfl));
		if (min(p1.x, p2.x) <= crp.x && crp.x <= max(p1.x, p2.x) && min(p1.y, p2.y) <= crp.y && crp.y <= max(p1.y, p2.y)) {
			bool ok = true;
			for (int j = 0; j < n; ++j) {
				point2d pp1 = v[j + 2], pp2 = v[(j + 1) % (v.size() - 2) + 2];
				if (intersect(segment2d(pp1, pp2), segment2d(v[0], v[1]))) {
					ok = false;
				}
			}
			if (ok) {
				double d0 = (crp - v[0]).abs();
				double d1 = (crp - v[1]).abs();
				ans = min(ans, d0 + d1);
			}
		}
	}
	cout << fixed << setprecision(15) << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3360
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef complex<double> P;
typedef complex<double> V;
typedef vector<P> vecP;
typedef pair<P,P> L;
typedef pair<P,P> S;
typedef pair<P,double> C;
const double eps=1e-8;
const double PI=acos(-1);
const double PI2=PI*2.0;
 
namespace std{
  bool operator < (const P &a,const P &b){
    return (a.real()!=b.real()?
            a.real() <b.real():
            a.imag() <b.imag());
  }
};
 
V normal(V a){
  assert( abs(a)>0 );
  return a/abs(a);
}
 
double Sqrt( double x ){
  if(x<0)return 0;
  else return sqrt(x);
}
 
P Vector(L a){
  return a.second-a.first;
}
 
bool eq(double a,double b){
  return (-eps<a-b&&a-b<eps);
}
 
bool eq(P a,P b){
  return ( eq(a.real(),b.real()) && eq(a.imag(),b.imag()) );
}
 
double dot(P a,P b){
  return real(b*conj(a));
}
 
double cross(P a,P b){
  return imag(b*conj(a));
}
 
double getArg(P a,P b){
  return arg(b*conj(a));
}
 
double getTime(V a,V b){
  assert( eq(cross(a,b),0) );
  return ( dot(a,b) < 0 ? -1.0 : 1.0 ) * abs(b) / abs(a);
}
 
 
P project(P a,P b,P c){
  b-=a,c-=a;
  return a+b*real(c/b);
}
 
P reflect(P a,P b,P c){
  b-=a,c-=a;
  return a+b*conj(c/b);
}
 
int ccw(P a,P b,P c){
  P ab=b-a,ac=c-a;
  P k=ac*conj(ab);
  if(k.imag()>0)return 1;
  if(k.imag()<0)return -1;
  if(k.real()<0)return 2;
  if(abs(ab)<abs(ac))return -2;
  return 0;
}
 
bool isParallel(P a,P b){
  return eq(0, cross(a,b));
}
 
bool isParallel(S a,S b){
  return eq(0, cross( Vector(a) , Vector(b) ) );
}
 
bool onLP(L l,P p){
  P a=l.first, b=l.second;
  return eq(0, cross(b-a,p-a));
}
 
bool onSP(S s,P p){
  return ( ccw(s.first, s.second ,p) == 0 );
}
 
bool isCrossSS(S s0,S s1){
  P a=s0.first, b=s0.second;
  P c=s1.first, d=s1.second;
  int f0 = ccw(a,b,c) * ccw(a,b,d);
  int f1 = ccw(c,d,a) * ccw(c,d,b);
  return (f0<=0 && f1<=0);
}
 
bool isCrossLS(L l,S s){
  P a=l.first, b=l.second;
  P c=s.first, d=s.second;
  return ( ccw(a,b,c) * ccw(a,b,d) <= 0 );
}
 
double distLP(L l,P p){
  P a=l.first, b=l.second;
  double res = cross(b-a,p-a) / abs(b-a);
  return abs(res);
}
 
double distSP(S s,P p){
  P a=s.first, b=s.second;
  if( dot(b-a,p-a) < eps )return abs(p-a);
  if( dot(a-b,p-b) < eps )return abs(p-b);
  return distLP(s,p);
}
 
double distSS(S s0,S s1){
  if( isCrossSS(s0,s1) )return 0;
  double res0 = min( distSP( s0, s1.first ) , distSP(s0, s1.second) );
  double res1 = min( distSP( s1, s0.first ) , distSP(s1, s0.second) );
  return min(res0,res1);
}
 
P getCrossLL(L l0,L l1){
  P a=l0.first, b=l0.second;
  P c=l1.first, d=l1.second;
  a-=d;b-=d;c-=d;
  return d+a+(b-a)*imag(a/c)/imag(a/c-b/c);
}
 
 
  
int inPolygon(vecP &t,P p){
  int n=t.size();
  double sum=0;
  for(int i=0;i<n;i++){
    P a=t[i],b=t[(i+1==n?0:i+1)];
    if( ccw(a,b,p)==0 )return 1;
    sum+= getArg(a-p,b-p);
  }
  if( abs(sum) < eps )return 0;
  else return 2;
}
 
vecP andrewScan(vecP &t){
  int N=t.size(),C=0;
  vecP R(N);
  for(int i=0;i<N;i++){
    while(2<=C&&ccw(R[C-2],R[C-1],t[i])==-1)C--;
    R[C++]=t[i];
  }
  vecP res(C);
  for(int i=0;i<C;i++)res[i]=R[i];
  return res;
}
  
vecP convexHull(vecP &t){
  sort(t.begin(),t.end());
  vecP u=andrewScan(t);
  reverse(t.begin(),t.end());
  vecP l=andrewScan(t);
  for(int i=1;i+1<(int)l.size();i++)u.push_back(l[i]);
  return u;
}
 
vecP cutConvex(vecP &t,L l){
  P a=l.first, b=l.second;
  int N=t.size();
  vecP res;
  for(int i=0;i<N;i++){
    P c=t[i],d=t[(i+1)%N];
    int C=ccw(a,b,c),D=ccw(a,b,d);
    if(C!=-1)res.push_back(c);
    if(C==-D&&abs(C)==1)res.push_back(getCrossLL( l ,L(c,d) ));
  }
  return res;
}
 
P getVector(const vecP &t, int id){
  int n=t.size();
  return t[ (id+1)%n ] - t[id%n];
}
 
double convex_diameter(vecP &t) {
  int n = t.size();
  int is = 0, js = 0;
  for (int i = 1; i < n; ++i) {
    if (imag(t[i]) > imag(t[is])) is = i;
    if (imag(t[i]) < imag(t[js])) js = i;
  }
  double maxd = norm(t[is]-t[js]);
  
  int i, maxi, j, maxj;
  i = maxi = is;
  j = maxj = js;
  do {
     
    if (cross( getVector(t,i), getVector(t,j)) >= 0) j = (j+1) % n;
     
    else i = (i+1) % n;
    if (norm(t[i]-t[j]) > maxd) {
      maxd = norm(t[i]-t[j]);
      maxi = i; maxj = j;
    }
  } while (i != is || j != js);
  return sqrt(maxd); /* farthest pair is (maxi, maxj). */
}
 
bool compare_y(const P &a,const P &b){
  return a.imag() < b.imag();
}
 
double closest_pair(P *a, int n){
  if(n <= 1) return 1e30;
  int m = n / 2;
  double x = a[m].real();
  double d = min(closest_pair(a, m), closest_pair(a + m, n - m));
  inplace_merge(a, a + m, a + n, compare_y);
  vector<P> b;
  for(int i=0;i<n;i++){
    if( abs(a[i].real() - x) >= d) continue;
    for(int j=0;j<(int)b.size();j++){
      double dx = real(a[i] - b[b.size() - j - 1]);
      double dy = imag(a[i] - b[b.size() - j - 1]);
      if(dy >= d) break;
      d = min(d, sqrt(dx * dx + dy * dy));
    }
    b.push_back(a[i]);
  }
  return d;
}
 
P _pool[200005];
double minDist(vecP &t){
  int n=t.size();
  for(int i=0;i<n;i++)_pool[i]=t[i];
  sort( _pool, _pool+n);
  return closest_pair(_pool, n);
}
 
int getStateCC(C a,C b){
  double ar=a.second, br=b.second;
  double dist=abs(a.first-b.first);
  if(dist>ar+br+eps)return 4;
  if(dist>ar+br-eps)return 3;
  if(dist>abs(ar-br)+eps)return 2;
  if(dist>abs(ar-br)-eps)return 1;
  return 0;
}
 
P getCrossCC(C a,C b){
  P p1=a.first, p2=b.first;
  double r1=a.second, r2=b.second;
  double cA = (r1*r1+norm(p1-p2)-r2*r2) / (2.0*r1*abs(p1-p2));
  return p1+(p2-p1)/abs(p1-p2)*r1*P(cA,Sqrt(1.0-cA*cA));
}
 
P getTangentCP_(C a,P p,int flg){
  P base=a.first-p;
  double ar=a.second;
  double w=Sqrt(norm(base)-ar*ar);
  P s=p+base*P(w,ar * flg)/norm(base)*w;
  return s;
}
 
vector<S> getTangentCP(C a,P p){
  vector<S> res;
  P s=getTangentCP_(a,p,1);
  P t=getTangentCP_(a,p,-1);
   
  if( eq(s,t) ){
    res.push_back( S(s, s+(a.first-p)*P(0,1) ) ); 
  }else{
    res.push_back( S(p,s) );
    res.push_back( S(p,t) );
  }
  return res;
}
 
S getInTangent(C a,C b,double flg=1.0){
  P ap=a.first,bp=b.first;
  double ar=a.second,br=b.second;
   
  P base=bp-ap;
  double w=ar+br;
  double h=Sqrt(norm(base)-w*w);
  P k=base*P(w,h*flg)/norm(base);
  return S(ap+k*ar,bp-k*br);
}
   
S getOutTangent(C a,C b,double flg=1.0){
  P ap=a.first,bp=b.first;
  double ar=a.second,br=b.second;
   
  P base=bp-ap;
  double h=br-ar;
   
  double w=Sqrt(norm(base)-h*h);
  P k=base*P(w,h*flg)/norm(base)*P(0,flg);
  return S(ap+k*ar,bp+k*br);
}
   
vector<S> getTangentCC(C a,C b){
  P ap=a.first,bp=b.first;
  double ar=a.second,br=b.second;
   
  vector<S> res;
  double dist=abs(ap-bp);
     
  if(dist>ar+br+eps)
    res.push_back(getInTangent(a,b,1));
   
  if(dist>ar+br-eps)
    res.push_back(getInTangent(a,b,-1));
   
  if(dist>abs(ar-br)+eps)
    res.push_back(getOutTangent(a,b,1));
   
  if(dist>abs(ar-br)-eps)
    res.push_back(getOutTangent(a,b,-1));
   
  return res;
}
 
 
vecP getCrossCL(C cir,L l){
  P a=l.first, b=l.second;
  double cr=cir.second;
  P cp=cir.first;
   
  vecP res;
  P base=b-a,  target=project(a,b,cp);
   
  double length=abs(base), h=abs(cp-target);
  base/=length;
   
  if(cr+eps<h)return res;
  double w=Sqrt(cr*cr-h*h);
  double L=getTime( normal(b-a) ,target-a)-w,  R=L+w*2.0;
   
  res.push_back(a+base*L);
  if( eq(L,R) )return res;
  res.push_back(a+base*R);
 
  return res;
}
 
vecP getCrossCS(C cir,S s){
  vecP tmp=getCrossCL(cir,s);
  vecP res;
  for(int i=0;i<(int)tmp.size();i++)
    //  if( ccw(s.first,s.second, tmp[i] ) == 0)
    if( onSP( s, tmp[i] ) )
      res.push_back(tmp[i]);
  return res;
}
 
double getArea(C c,P a,P b){
  P cp=c.first;
  double cr=c.second;
   
  P va=cp-a,  vb=cp-b;
  double A=abs(va), B=abs(vb);
  double f=cross(va,vb), d=distSP( S(a,b) ,cp), res=0;
   
  if( eq(0, f ) )return 0;
  if(A<cr+eps&&B<cr+eps)return f*0.5;
  if(d>cr-eps)return cr*cr*PI*getArg(va,vb)/PI2;
    
  vecP u=getCrossCS(c, S(a,b) );
   
  assert( !u.empty() );
  u.insert(u.begin(), a),  u.push_back(b);
  
  for(int i=0;i+1<(int)u.size();i++) res+=getArea(c,u[i],u[i+1]);
  return res;
}
  
double getCrossArea(vecP t,C c){
  int n=t.size();
  if(n<3)return 0;
  double res=0;
  for(int i=0;i<n;i++){
    P a=t[i], b=t[(i+1)%n];
    res+=getArea(c,a,b);
  }
  return res;
}
 
 
double calcPolygonArea(const vecP &t){
  double res=0;
  int n=t.size();
  for(int i=0;i<n;i++){
    res+= cross( t[ (i+1)%n ],t[i] );
  }
  return abs(res)*0.5;
}

bool check( vecP &A, P s,P t,bool f=false){
  int n=A.size();
  for(int i=0;i<n;i++){
    P a=A[i];
    P b=A[(i+1)%n];
    if( isParallel( a-b, s-t) )continue;
    if( !isCrossSS( S(a,b) , S(s,t) ) )continue;

    if( f )return false;
    
    P p=getCrossLL( L(a,b) , L(s,t) );
    int cnt=0;
    if( eq(p,a) )cnt++;
    if( eq(p,b) )cnt++;
    if( eq(p,s) )cnt++;
    if( eq(p,t) )cnt++;
    if(cnt<=1) return false;
  }
  return true;
}

int main(){
  double G[200][200];
  int n;
  vecP A;
  P s,t;
  int sx,sy,tx,ty;
  cin>>sx>>sy>>tx>>ty;
  s=P(sx,sy);
  t=P(tx,ty);
  cin>>n;
  for(int i=0;i<n;i++){
    int x,y;
    cin>>x>>y;
    A.push_back(P(x,y));
  }
  

  double ans=1e9;
  if(  check(A,s,t,true) ){
    for(int i=0;i<n;i++){
      ans=min(ans, abs(A[i]-s) + abs(A[i]-t) );
      int j=(i+1)%n;
      P nt=reflect(A[i],A[j],t);
      if( isCrossSS( S(s,nt) , S(A[i],A[j]) ) )
        ans=min(ans, abs(s - nt ) );
    }
  }else{
    
    for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
        G[i][j]=(i==j? 0.0 : 1e9 );
    
    for(int i=0;i<n;i++){
      int j=(i+1)%n;
      G[i][j]=G[j][i]=abs(A[i]-A[j]);
    }
    
    for(int k=0;k<n;k++)
      for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
          G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
    
    for(int i=0;i<n;i++){
      if(check(A,s,A[i])){
        for(int j=0;j<n;j++){
          if(check(A,A[j],t)){
            ans=min(ans,abs(A[i]-s) + abs(A[j]-t) + G[i][j]);
          }
        }
      }
    }
    
  }
  printf("%.10f\n",ans);
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6608
final_rank: 6

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define pb push_back
#define dbg(...) do{cerr<<__LINE__<<": ";dbgprint(#__VA_ARGS__, __VA_ARGS__);}while(0);

using namespace std;

namespace std{template<class S,class T>struct hash<pair<S,T>>{size_t operator()(const pair<S,T>&p)const{return ((size_t)1e9+7)*hash<S>()(p.first)+hash<T>()(p.second);}};template<class T>struct hash<vector<T>>{size_t operator()(const vector<T> &v)const{size_t h=0;for(auto i : v)h=h*((size_t)1e9+7)+hash<T>()(i)+1;return h;}};}
template<class T>ostream& operator<<(ostream &os, const vector<T> &v){os<<"[ ";rep(i,v.size())os<<v[i]<<(i==v.size()-1?" ]":", ");return os;}template<class T>ostream& operator<<(ostream &os,const set<T> &v){os<<"{ "; for(const auto &i:v)os<<i<<", ";return os<<"}";}
template<class T,class U>ostream& operator<<(ostream &os,const map<T,U> &v){os<<"{";for(const auto &i:v)os<<" "<<i.first<<": "<<i.second<<",";return os<<"}";}template<class T,class U>ostream& operator<<(ostream &os,const pair<T,U> &p){return os<<"("<<p.first<<", "<<p.second<<")";}
void dbgprint(const string &fmt){cerr<<endl;}template<class H,class... T>void dbgprint(const string &fmt,const H &h,const T&... r){cerr<<fmt.substr(0,fmt.find(","))<<"= "<<h<<" ";dbgprint(fmt.substr(fmt.find(",")+1),r...);}
typedef long long ll;typedef vector<int> vi;typedef pair<int,int> pi;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<double> P;
namespace std{
	bool operator<(const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
inline double cross(const P& a, const P& b){ return imag(conj(a)*b); }
inline double dot(const P& a, const P& b){ return real(conj(a)*b); }
struct L : public vector<P>{
	L(const P &a, const P &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<P> G;
inline int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if(cross(b, c) >  EPS)   return +1;      // counter clockwise
	if(cross(b, c) < -EPS)   return -1;      // clockwise
	if(dot(b, c)   < -EPS)   return +2;      // c--a--b on line
	if(norm(b)+EPS <norm(c)) return -2;      // a--b--c on line
	return 0;                                   // c is between a and b (inclusive)
}
bool intersectSS(const L &s, const L &t) {
  return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) < 0 &&
         ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) < 0;
}
int main(){
	cin.tie(0); cin.sync_with_stdio(0);
	P s, t;
	G ps;
	int x, y, n;
	cin >> x >> y; s = P(x, y);
	cin >> x >> y; t = P(x, y);
	cin >> n;
	rep(i, n){
		cin >> x >> y;
		ps.emplace_back(x, y);
	}
	vector<vector<double>> d(n, vector<double>(n, INF));
	rep(i, n){
		d[i][i] = 0;
		d[(i + 1) % n][i] = d[i][(i + 1) % n] = abs(ps[i] - ps[(i + 1) % n]);
	}
	rep(k, n) rep(i, n) rep(j, n) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
	
	auto ok = [&](const P &a, const P &b){
		const L l(a, b);
		rep(i, n){
			if(intersectSS(l, L(ps[i], ps[(i + 1) % n]))) return 0;
			if(ccw(ps[i], l[0], l[1]) == 2) return 0;
		}
		return 1;
	};
	
	double ans = INF;
	rep(i, n) rep(j, n){
		if(!ok(s, ps[i])) continue;
		if(!ok(t, ps[j])) continue;
		ans = min(ans, abs(s - ps[i]) + d[i][j] + abs(t - ps[j]));
	}
	#if 1
	int cnt = 0;
	rep(i, n){
		P a = ps[i], b = ps[(i + 1) % n];
		if(!(ok(s, a) && ok(s, b) && ok(t, a) && ok(t, b))) continue;
		double lo = 0, hi = 1, l, r;
		rep(it, 100){
			l = (2 * lo + hi) / 3;
			r = (lo + 2 * hi) / 3;
			P p1 = a * (1 - l) + b * l;
			P p2 = a * (1 - r) + b * r;
			if(abs(p1 - s) + abs(p1 - t) < abs(p2 - s) + abs(p2 - t)) hi = r;
			else lo = l;
		}
		P p = a * (1 - lo) + b * lo;
		ans = min(ans, abs(p - s) + abs(p - t));
		//assert(++cnt <= 2);
	}
	#endif
	printf("%.20f\n", ans);
	
	return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3440
final_rank: 5

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define pb push_back
#define dbg(...) do{cerr<<__LINE__<<": ";dbgprint(#__VA_ARGS__, __VA_ARGS__);}while(0);

using namespace std;

namespace std{template<class S,class T>struct hash<pair<S,T>>{size_t operator()(const pair<S,T>&p)const{return ((size_t)1e9+7)*hash<S>()(p.first)+hash<T>()(p.second);}};template<class T>struct hash<vector<T>>{size_t operator()(const vector<T> &v)const{size_t h=0;for(auto i : v)h=h*((size_t)1e9+7)+hash<T>()(i)+1;return h;}};}
template<class T>ostream& operator<<(ostream &os, const vector<T> &v){os<<"[ ";rep(i,v.size())os<<v[i]<<(i==v.size()-1?" ]":", ");return os;}template<class T>ostream& operator<<(ostream &os,const set<T> &v){os<<"{ "; for(const auto &i:v)os<<i<<", ";return os<<"}";}
template<class T,class U>ostream& operator<<(ostream &os,const map<T,U> &v){os<<"{";for(const auto &i:v)os<<" "<<i.first<<": "<<i.second<<",";return os<<"}";}template<class T,class U>ostream& operator<<(ostream &os,const pair<T,U> &p){return os<<"("<<p.first<<", "<<p.second<<")";}
void dbgprint(const string &fmt){cerr<<endl;}template<class H,class... T>void dbgprint(const string &fmt,const H &h,const T&... r){cerr<<fmt.substr(0,fmt.find(","))<<"= "<<h<<" ";dbgprint(fmt.substr(fmt.find(",")+1),r...);}
typedef long long ll;typedef vector<int> vi;typedef pair<int,int> pi;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<double> P;
namespace std{
	bool operator<(const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
inline double cross(const P& a, const P& b){ return imag(conj(a)*b); }
inline double dot(const P& a, const P& b){ return real(conj(a)*b); }
struct L : public vector<P>{
	L(const P &a, const P &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<P> G;
inline int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if(cross(b, c) >  EPS)   return +1;      // counter clockwise
	if(cross(b, c) < -EPS)   return -1;      // clockwise
	if(dot(b, c)   < -EPS)   return +2;      // c--a--b on line
	if(norm(b)+EPS <norm(c)) return -2;      // a--b--c on line
	return 0;                                   // c is between a and b (inclusive)
}
bool intersectSS(const L &s, const L &t) {
  return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) < 0 &&
         ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) < 0;
}
int main(){
	cin.tie(0); cin.sync_with_stdio(0);
	P s, t;
	G ps;
	int x, y, n;
	cin >> x >> y; s = P(x, y);
	cin >> x >> y; t = P(x, y);
	cin >> n;
	rep(i, n){
		cin >> x >> y;
		ps.emplace_back(x, y);
	}
	vector<vector<double>> d(n, vector<double>(n, INF));
	rep(i, n){
		d[i][i] = 0;
		d[(i + 1) % n][i] = d[i][(i + 1) % n] = abs(ps[i] - ps[(i + 1) % n]);
	}
	rep(k, n) rep(i, n) rep(j, n) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
	
	auto ok = [&](const P &a, const P &b){
		const L l(a, b);
		rep(i, n){
			if(intersectSS(l, L(ps[i], ps[(i + 1) % n]))) return 0;
			if(ccw(ps[i], l[0], l[1]) == 2) return 0;
		}
		return 1;
	};
	
	double ans = INF;
	rep(i, n) rep(j, n){
		if(!ok(s, ps[i])) continue;
		if(!ok(t, ps[j])) continue;
		ans = min(ans, abs(s - ps[i]) + d[i][j] + abs(t - ps[j]));
	}
	#if 1
	int cnt = 0;
	rep(i, n){
		P a = ps[i], b = ps[(i + 1) % n];
		if(!(ok(s, a) && ok(s, b) && ok(t, a) && ok(t, b))) continue;
		double lo = 0, hi = 1, l, r;
		rep(it, 100){
			l = (2 * lo + hi) / 3;
			r = (lo + 2 * hi) / 3;
			P p1 = a * (1 - l) + b * l;
			P p2 = a * (1 - r) + b * r;
			if(abs(p1 - s) + abs(p1 - t) < abs(p2 - s) + abs(p2 - t)) hi = r;
			else lo = l;
		}
		P p = a * (1 - lo) + b * lo;
		ans = min(ans, abs(p - s) + abs(p - t));
		assert(++cnt <= 2);
	}
	#endif
	printf("%.20f\n", ans);
	
	return 0;
}
accuracy: 0.625
time_ms: 50
memory_kb: 3396
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;

using D = double;
struct Point {
  D x, y;
  Point(const D d = 0.0) : x(d), y(d) {}
  Point(const D x, const D y) : x(x), y(y) {}
};
struct Segment {
  Point ab, to;
  Segment(const Point& ab, const Point& to) : ab(ab), to(to) {}
  Segment(const D x1, const D y1, const D x2, const D y2) : ab(x1, y1), to(x2, y2) {}
};
using Polygon = vector<Point>;

const D EPS = 1e-9;
enum POSITION {ONLINE_FRONT = -2, CLOCKWISE, ON_SEGMENT, COUNTER_CLOCKWISE, ONLINE_BACK};

bool relative_equal(const D d1, const D d2) {return d1 == 0 ? std::abs(d2) < EPS : std::abs((d1 - d2) / d1) < EPS;}
bool operator==(const Point& lhs, const Point& rhs) {return relative_equal(lhs.x, rhs.x) && relative_equal(lhs.y, rhs.y);}
bool operator<(const Point& lhs, const Point& rhs) {return relative_equal(lhs.x, rhs.x) ? lhs.y < rhs.y : lhs.x < rhs.x;}
bool operator>(const Point& lhs, const Point& rhs) {return relative_equal(lhs.x, rhs.x) ? lhs.y > rhs.y : lhs.x > rhs.x;}
bool operator!=(const Point& lhs, const Point& rhs) {return !(lhs == rhs);}
bool operator<=(const Point& lhs, const Point& rhs) {return !(lhs > rhs);}
bool operator>=(const Point& lhs, const Point& rhs) {return !(lhs < rhs);}
const Point operator+(const Point& lhs, const Point& rhs) {return Point(lhs.x + rhs.x, lhs.y + rhs.y);}
const Point operator-(const Point& lhs, const Point& rhs) {return Point(lhs.x - rhs.x, lhs.y - rhs.y);}
const Point operator*(const Point& lhs, const Point& rhs) {return Point(lhs.x * rhs.x, lhs.y * rhs.y);}
const Point operator/(const Point& lhs, const Point& rhs) {return Point(lhs.x / rhs.x, lhs.y / rhs.y);}
D abs(const Point& p) {return hypot(p.x, p.y);}
D norm(const Point& p) {return p.x * p.x + p.y * p.y;}
D dot(const Point& a, const Point& b) {return a.x * b.x + a.y * b.y;}
D cross(const Point& a, const Point& b) {return a.x * b.y - a.y * b.x;}
POSITION ccw(const Point& a, const Point& b, const Point& p) {
  Point v1 = b - a;
  Point v2 = p - a;
  if(cross(v1, v2) >= EPS) return COUNTER_CLOCKWISE;
  if(cross(v1, v2) <= -EPS) return CLOCKWISE;
  if(dot(v1, v2) <= -EPS) return ONLINE_BACK;
  if(norm(v1) < norm(v2)) return ONLINE_FRONT;
  return ON_SEGMENT;
}
ostream& operator<<(ostream& os, const Point& p) {os<<"point: "; os<<"("<<p.x<<","<<p.y<<")"; return os;}

bool intersect(Segment s, Segment t) {return ccw(s.ab, s.to, t.ab)*ccw(s.ab, s.to, t.to) <= 0 && ccw(t.ab, t.to, s.ab)*ccw(t.ab, t.to, s.to) <= 0;}

bool intersect(Polygon P, Segment S) {
  for(auto i = 0; i < P.size(); ++i) {
    Segment T(P[i], P[(i+1) % P.size()]);
    if(intersect(S, T)) return true;
  }
  return false;
}

D tsearch(auto S, auto G, auto P) {
  auto d = [&](auto p) {return abs(p - S) + abs(G - p);};
  auto point = [&](auto p, auto q, auto x) {return p + (q - p) * x;};
  D r = 1e9;
  for(auto i = 0; i < P.size(); ++i) {
    auto s = P[i], g = P[(i+1) % P.size()];
    D l = 0, h = 1;
    for(auto j = 0; j < 1000; ++j) {
      auto m1 = (h + 2 * l) / 3;
      auto m2 = (2 * h + l) / 3;
      auto d1 = d(point(s, g, m1));
      auto d2 = d(point(s, g, m2));
      if(d1 < d2) h = m2;
      else        l = m1;
    }
    r = min(r, d(point(s, g, h)));
  }
  return r;
}

D chull(auto S, auto G, auto P) {
  if(S > G) swap(S, G);
  P.emplace_back(S);
  P.emplace_back(G);
  sort(begin(P), end(P));
  P.insert(end(P), P.rbegin() + 1, P.rend());
  Polygon ch;
  for(const auto& p: P) {
    while(ch.size() >= 2 && ccw(ch[ch.size() - 2], ch.back(), p) == CLOCKWISE) ch.pop_back();
    ch.emplace_back(p);
  }
  ch.pop_back();

  auto solve = [&](auto b, auto e) {
    D res = 0;
    auto pass = false;
    for(auto i = 0; i < 2 * ch.size(); ++i) {
      auto p = ch[i % ch.size()], q = ch[(i + 1) % ch.size()];
      if(p == b) pass = true;
      if(!pass) continue;
      res += abs(p - q);
      if(q == e) return res;
    }
    return 1e9;
  };
  return min(solve(S, G), solve(G, S));
}

int main() {
  Point S, G;
  int N;
  cin >> S.x >> S.y >> G.x >> G.y >> N;

  Polygon P(N);
  for(auto& i: P) cin >> i.x >> i.y;

  if(intersect(P, Segment{S, G})) cout << setprecision(8) << fixed << chull(S, G, P) << endl;
  else                            cout << setprecision(8) << fixed << tsearch(S, G, P) << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 3360
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

typedef double D;
typedef complex<D>Point;
typedef vector<Point>Polygon;

const D EPS=1e-5;

const int COUNTER_CLOCKWISE=1;
const int CLOCKWISE=-1;
const int ONLINE_FRONT=2;
const int ONLINE_BACK=-2;
const int ON_SEGMENT=0;

struct Segment{
    Point p1,p2;
    Segment(const Point &p1=Point(),const Point &p2=Point()):p1(p1),p2(p2){}
};

istream& operator>>(istream &is,Point &a){
    D x,y;
    is>>x>>y;
    a=Point(x,y);
    return is;
}

D dot(const Point &a,const Point &b){
    return real(a)*real(b)+imag(a)*imag(b);
}
D cross(const Point &a,const Point &b){
    return real(a)*imag(b)-real(b)*imag(a);
}

Point projection(const Point &a,const Point &b){
    return a*real(b/a);
}

Point projection(const Segment &s,const Point &a){
    return s.p1+projection(s.p2-s.p1,a-s.p1);
}

Point reflection(const Segment &s,const Point &a){
    Point p=projection(s,a);
    return 2.0*p-a;
}

int ccw(Point a,Point b,Point c){
    b-=a;c-=a;
    if(cross(b,c)>EPS)return COUNTER_CLOCKWISE;
    if(cross(b,c)<-EPS)return CLOCKWISE;
    if(dot(b,c)<-EPS)return ONLINE_BACK;
    if(norm(b)+EPS<norm(c))return ONLINE_FRONT;
    return ON_SEGMENT;
}

bool intersect(const Point &a1,const Point a2,const Point &b1,const Point &b2){
    return ccw(a1,a2,b1)*ccw(a1,a2,b2)<=0&&
    ccw(b1,b2,a1)*ccw(b1,b2,a2)<=0;
}

signed main(){
    Point A,B;
    cin>>A>>B;

    int N;cin>>N;
    Polygon G(N);
    rep(i,N)cin>>G[i];

    double ans=1e18;

        rep(i,N){
            if(ccw(G[i],G[(i+1)%N],A)==CLOCKWISE&&ccw(G[i],G[(i+1)%N],B)==CLOCKWISE){
                Point p=reflection(Segment(G[i],G[(i+1)%N]),B);
                if(intersect(G[i],G[(i+1)%N],A,p))chmin(ans,abs(p-A));
            }
        }

        vint okA(N),okB(N);
        rep(i,N){
            if(ccw(G[(i-1+N)%N],G[i],A)!=COUNTER_CLOCKWISE||ccw(G[i],G[(i+1)%N],A)!=COUNTER_CLOCKWISE)okA[i]=true;
            if(ccw(G[(i-1+N)%N],G[i],B)!=COUNTER_CLOCKWISE||ccw(G[i],G[(i+1)%N],B)!=COUNTER_CLOCKWISE)okB[i]=true;
        }

        rep(i,N){
            if(!okA[i])continue;
            rep(j,N){
                if(!okB[j])continue;
                double tmp=abs(G[i]-A)+abs(G[j]-B);
                int v=i;
                while(v!=j){
                    tmp+=abs(G[v]-G[(v+1)%N]);
                    v=(v+1)%N;
                }
                chmin(ans,tmp);


                tmp=abs(G[i]-A)+abs(G[j]-B);
                v=i;
                while(v!=j){
                    tmp+=abs(G[v]-G[(v-1+N)%N]);
                    v=(v-1+N)%N;
                }
                chmin(ans,tmp);
            }
        }



    printf("%.20f\n",ans);
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3264
final_rank: 1

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

using namespace std;

const double EPS = 1e-8, PI = acos(-1);

inline bool eq(double a, double b) { return fabs(b - a) < EPS; }

struct Point
{
  double x, y;

  Point() {}

  Point(double x, double y) : x(x), y(y) {}

  Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

  Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

  Point operator*(const double b) const { return Point(x * b, y * b); }

  Point operator*(const Point &b) const { return Point(x * b.x - y * b.y, x * b.y + y * b.x); }

  Point operator/(const double b) const { return Point(x / b, y / b); }

  bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

  bool operator==(const Point &b) const { return eq(x, b.x) && eq(y, b.y); }

  double norm() { return x * x + y * y; }

  double arg() { return atan2(x, y); }

  double abs() { return sqrt(norm()); }

  Point rotate(double theta) { return Point(cos(theta) * x - sin(theta) * y, sin(theta) * x + cos(theta) * y); }

  Point rotate90() { return Point(-y, x); }

  friend ostream &operator<<(ostream &os, Point &p) { return os << "(" << p.x << "," << p.y << ")"; }

  friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
};

double cross(const Point &a, const Point &b)
{
  return a.x * b.y - a.y * b.x;
}

double dot(const Point &a, const Point &b)
{
  return a.x * b.x + a.y * b.y;
}

double RadianToDegree(double r)
{
  return (r * 180.0 / acos(-1));
}

double DegreeToRadian(double d)
{
  return (d * acos(-1) / 180.0);
}

double GetAngle(const Point &a, const Point &b, const Point &c)
{
  const Point v = b - a, w = c - b;
  double alpha = atan2(v.y, v.x), beta = atan2(w.y, w.x);
  if(alpha > beta) swap(alpha, beta);
  double theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

struct Line
{
  Point a, b;

  Line() {};

  Line(Point a, Point b) : a(a), b(b) {};

  // Ax + By = C
  Line(double A, double B, double C)
  {
    if(eq(A, 0)) {
      a = Point(0, C / B);
      b = Point(1, C / B);
    } else if(eq(B, 0)) {
      a = Point(C / A, 0);
      b = Point(C / A, 1);
    } else {
      a = Point(0, C / B);
      b = Point(C / A, 0);
    }
  }

  friend ostream &operator<<(ostream &os, Line &p) { return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << "," << p.b.y << ")"; }

  friend istream &operator>>(istream &is, Line &a) { return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y; }
};

struct Segment
{
  Point a, b;

  Segment() {};

  Segment(Point a, Point b) : a(a), b(b) {};

  friend ostream &operator<<(ostream &os, Segment &p) { return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << "," << p.b.y << ")"; }

  friend istream &operator>>(istream &is, Segment &a) { return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y; }
};

typedef vector< Point > Polygon;

int ccw(const Point &a, Point b, Point c)
{
  b = b - a, c = c - a;
  if(cross(b, c) > EPS) return +1;
  if(cross(b, c) < -EPS) return -1;
  if(dot(b, c) < 0) return +2;
  if(b.norm() < c.norm()) return -2;
  return 0;
}

bool Intersect(const Segment &s, const Segment &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;
}

bool Intersect(const Segment &s, const Point &p)
{
  return ccw(s.a, s.b, p) == 0;
}

void WarshallFloyd(vector< vector< double > > &g)
{
  for(int k = 0; k < g.size(); k++) {
    for(int i = 0; i < g.size(); i++) {
      for(int j = 0; j < g.size(); j++) {
        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
      }
    }
  }
}


int main()
{
  Point pt[2];
  cin >> pt[0] >> pt[1];
  int N;
  cin >> N;
  Polygon ps(N);
  for(auto &p : ps) cin >> p;

  vector< vector< double > > g(N + 2, vector< double >(N + 2, 1e9));
  for(int i = 0; i < g.size(); i++) g[i][i] = 0;

  auto add = [&](int u, int v, double cost)
  {
    g[u][v] = g[v][u] = min(g[v][u], cost);
  };

  for(int i = 0; i < N; i++) {
    add(i, (i + 1) % N, (ps[i] - ps[(i + 1) % N]).abs());
  }
  for(int i = 0; i < 2; i++) {
    for(int j = 0; j < N; j++) {
      Segment base(pt[i], ps[j]);
      bool intersect = false;
      for(int k = 0; k < N; k++) {
        if(j == k) continue;
        if(j == (k + 1) % N) continue;
        intersect |= Intersect((Segment) {ps[k], ps[(k + 1) % N]}, base);
      }
      if(!intersect) add(i + N, j, (base.a - base.b).abs());
    }
  }

  WarshallFloyd(g);
  double ret = g[N][N + 1];
  for(int i = 0; i < N; i++) {
    double low = 0, high = 1.0;
    Segment s(ps[i], ps[(i + 1) % N]);

    auto getDist = [&](double v)
    {
      Point peet = s.a + (s.b - s.a) * v;
      Segment latte = Segment(pt[0], peet);
      Segment malta = Segment(pt[1], peet);
      bool intersect = false;
      for(int k = 0; k < N; k++) {
        if(i == k) continue;
        intersect |= Intersect(latte, (Segment) {ps[k], ps[(k + 1) % N]});
        intersect |= Intersect(malta, (Segment) {ps[k], ps[(k + 1) % N]});
      }
      double dist = 1145141919;
      if(!intersect) dist = (latte.a - latte.b).abs() + (malta.a - malta.b).abs();
      return (dist);
    };

    for(int j = 0; j < 100; j++) {
      double left = (low * 2 + high) / 3;
      double right = (low + high * 2) / 3;

      if(getDist(left) < getDist(right)) high = right;
      else low = left;
    }
    ret = min(ret, getDist(low));
  }

  cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 3352
final_rank: 4

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

using namespace std;

const double EPS = 1e-8, PI = acos(-1);

inline bool eq(double a, double b) { return fabs(b - a) < EPS; }

struct Point
{
  double x, y;

  Point() {}

  Point(double x, double y) : x(x), y(y) {}

  Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

  Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

  Point operator*(const double b) const { return Point(x * b, y * b); }

  Point operator*(const Point &b) const { return Point(x * b.x - y * b.y, x * b.y + y * b.x); }

  Point operator/(const double b) const { return Point(x / b, y / b); }

  bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

  bool operator==(const Point &b) const { return eq(x, b.x) && eq(y, b.y); }

  double norm() { return x * x + y * y; }

  double arg() { return atan2(x, y); }

  double abs() { return sqrt(norm()); }

  Point rotate(double theta) { return Point(cos(theta) * x - sin(theta) * y, sin(theta) * x + cos(theta) * y); }

  Point rotate90() { return Point(-y, x); }

  friend ostream &operator<<(ostream &os, Point &p) { return os << "(" << p.x << "," << p.y << ")"; }

  friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
};

double cross(const Point &a, const Point &b)
{
  return a.x * b.y - a.y * b.x;
}

double dot(const Point &a, const Point &b)
{
  return a.x * b.x + a.y * b.y;
}

double RadianToDegree(double r)
{
  return (r * 180.0 / acos(-1));
}

double DegreeToRadian(double d)
{
  return (d * acos(-1) / 180.0);
}

double GetAngle(const Point &a, const Point &b, const Point &c)
{
  const Point v = b - a, w = c - b;
  double alpha = atan2(v.y, v.x), beta = atan2(w.y, w.x);
  if(alpha > beta) swap(alpha, beta);
  double theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

struct Line
{
  Point a, b;

  Line() {};

  Line(Point a, Point b) : a(a), b(b) {};

  // Ax + By = C
  Line(double A, double B, double C)
  {
    if(eq(A, 0)) {
      a = Point(0, C / B);
      b = Point(1, C / B);
    } else if(eq(B, 0)) {
      a = Point(C / A, 0);
      b = Point(C / A, 1);
    } else {
      a = Point(0, C / B);
      b = Point(C / A, 0);
    }
  }

  friend ostream &operator<<(ostream &os, Line &p) { return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << "," << p.b.y << ")"; }

  friend istream &operator>>(istream &is, Line &a) { return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y; }
};

struct Segment
{
  Point a, b;

  Segment() {};

  Segment(Point a, Point b) : a(a), b(b) {};

  friend ostream &operator<<(ostream &os, Segment &p) { return os << "(" << p.a.x << "," << p.a.y << ") to (" << p.b.x << "," << p.b.y << ")"; }

  friend istream &operator>>(istream &is, Segment &a) { return is >> a.a.x >> a.a.y >> a.b.x >> a.b.y; }
};

typedef vector< Point > Polygon;

int ccw(const Point &a, Point b, Point c)
{
  b = b - a, c = c - a;
  if(cross(b, c) > EPS) return +1;
  if(cross(b, c) < -EPS) return -1;
  if(dot(b, c) < 0) return +2;
  if(b.norm() < c.norm()) return -2;
  return 0;
}

bool Intersect(const Segment &s, const Segment &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;
}

bool Intersect(const Segment &s, const Point &p)
{
  return ccw(s.a, s.b, p) == 0;
}

void WarshallFloyd(vector< vector< double > > &g)
{
  for(int k = 0; k < g.size(); k++) {
    for(int i = 0; i < g.size(); i++) {
      for(int j = 0; j < g.size(); j++) {
        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
      }
    }
  }
}


int main()
{
  Point pt[2];
  cin >> pt[0] >> pt[1];
  int N;
  cin >> N;
  Polygon ps(N);
  for(auto &p : ps) cin >> p;

  vector< vector< double > > g(N + 2, vector< double >(N + 2, 1e9));
  for(int i = 0; i < g.size(); i++) g[i][i] = 0;

  auto add = [&](int u, int v, double cost)
  {
    g[u][v] = g[v][u] = min(g[v][u], cost);
  };

  for(int i = 0; i < N; i++) {
    add(i, (i + 1) % N, (ps[i] - ps[(i + 1) % N]).abs());
  }
  for(int i = 0; i < 2; i++) {
    for(int j = 0; j < N; j++) {
      Segment base(pt[i], ps[j]);
      bool intersect = false;
      for(int k = 0; k < N; k++) {
        if(j == k) continue;
        if(j == (k + 1) % N) continue;
        intersect |= Intersect((Segment) {ps[k], ps[(k + 1) % N]}, base);
      }
      if(!intersect) add(i + N, j, (base.a - base.b).abs());
    }
  }

  WarshallFloyd(g);
  double ret = g[N][N + 1];
  for(int i = 0; i < N; i++) {
    double low = 0, high = 1.0;
    Segment s(ps[i], ps[(i + 1) % N]);

    auto getDist = [&](double v)
    {
      Point peet = s.a + (s.b - s.a) * v;
      Segment latte = Segment(pt[0], peet);
      Segment malta = Segment(pt[1], peet);
      bool intersect = false;
      for(int k = 0; k < N; k++) {
        if(i == k) continue;
        intersect |= Intersect(latte, (Segment) {ps[k], ps[(k + 1) % N]});
        intersect |= Intersect(malta, (Segment) {ps[k], ps[(k + 1) % N]});
      }
      double dist = 1145141919;
      if(!intersect) dist = (latte.a - latte.b).abs() + (malta.a - malta.b).abs();
      return (dist);
    };

    for(int j = 0; j < 300; j++) {
      double left = (low * 2 + high) / 3;
      double right = (low + high * 2) / 3;

      if(getDist(left) < getDist(right)) high = right;
      else low = left;
    }
    ret = min(ret, getDist(low));
  }

  cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 1
time_ms: 90
memory_kb: 3368
final_rank: 7