#include<iostream>
#include<queue>
#include<fstream>
#include<map>
#include<cstdlib>
#include<algorithm>
#include<complex>
#include<vector>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C) (C).begin(),(C).end()
#define pb push_back
#define mp make_pair

typedef complex<double> P;
typedef pair<int,int> pii;
const double eps = 1e-10;

class pt{
public:
  double x,y;
  bool operator==(const pt & a)const{
    return fabs(a.x-x)<eps && fabs(y-a.y)<eps;
  }
};

double computex(double a,double x,double y,double syj){
  double b=y-a*x;
  return (syj-b)/a;
}

void lineonpoint(double x,double x1,double y,double y1,vector<pt> &all,
		 vector<double> &sy){
  rep(j,sy.size()){
    if (min(y,y1) <= sy[j] && sy[j] <= max(y,y1)){
      if (y == sy[j])all.pb((pt){x,y});
      else all.pb((pt){computex((y-y1)/(x-x1),x,y,sy[j]),sy[j]});
    }
  }
}

void makegraph(int n,vector<double> &x,vector<double> &y,vector<pt> &all){
  vector<double> sy=y;
  sort(ALL(sy));
  sy.erase(unique(ALL(sy)),sy.end());
  vector<double> rsy=sy;reverse(ALL(rsy));

  rep(i,x.size()-1){
    if (y[i] <= y[i+1]){
      lineonpoint(x[i],x[i+1],y[i],y[i+1],all,sy);
    }else {
      lineonpoint(x[i],x[i+1],y[i],y[i+1],all,rsy);
    }
    if (i+1 < x.size())all.pb((pt){x[i+1],y[i+1]});
  }
  all.erase(unique(ALL(all)),all.end());
}

class Edge{
public:
  int to;
  double cost;
};

const int N = 10010;
vector<Edge> edge[N];

double computeabs(pt &a,pt &b){
  double x=a.x-b.x,y=a.y-b.y;
  return sqrt(x*x+y*y);
}

void makeedge(vector<pt> & all){
  rep(i,all.size()){
    if (i >0)edge[i].pb((Edge){i-1,computeabs(all[i],all[i-1])});
    edge[i].pb((Edge){i,0});
    if (i+1 < all.size())edge[i].pb((Edge){i+1,computeabs(all[i],all[i+1])});
  }
}

class st{
public:
  int p1,p2;
  double cost;
  bool operator<(const st & a)const{
    return cost > a.cost;
  }
};

bool islow(map<pii,double> &M,int a,int b,double cost){
  pii hoge=mp(a,b);
  if (M.find(hoge) == M.end()){
    M[hoge]=cost;
    return true;
  }
  if (M[hoge] > cost){
    M[hoge]=cost;
    return true;
  }
  return false;
}

bool issame(map<pii,double> &M,int a,int b,double cost){
  pii hoge=mp(a,b);
  if (M.find(hoge) == M.end()){
    return false;
  }
  if (fabs(M[hoge]-cost) <  eps){
    return true;
  }
  return false;
}

double dijkstra(vector<pt> &all){
  map<pii,double> M;
  priority_queue<st> Q;
  Q.push((st){0,all.size()-1,0});
  M[mp(0,all.size()-1)]=0;
  while(!Q.empty()){
    st now = Q.top();Q.pop();
    if (!issame(M,now.p1,now.p2,now.cost))continue;
    //    cout << now.p1 <<" " << now.p2 <<" " << now.cost << endl;
    if (now.p1 == now.p2)return now.cost;
    rep(i,edge[now.p1].size()){
      rep(j,edge[now.p2].size()){
	if (fabs(all[edge[now.p1][i].to].y-all[edge[now.p2][j].to].y) < eps &&
	    islow(M,edge[now.p1][i].to,edge[now.p2][j].to,now.cost+edge[now.p1][i].cost+edge[now.p2][j].cost)){
	  //	  cout << now.p1 <<" to " << edge[now.p1][i].to << " cost " << edge[now.p1][i].cost << " : "  
	  //	       << now.p2 <<" to " << edge[now.p2][j].to << " cost " << edge[now.p2][j].cost << endl;
	  Q.push((st){edge[now.p1][i].to,edge[now.p2][j].to,
		now.cost+edge[now.p1][i].cost+edge[now.p2][j].cost});
	}
      }
    }
  }
}

main(){

  int n;
  while(cin>>n && n){
    vector<double> x(n),y(n);
    vector<pt> all;
    rep(i,n){
      cin>>x[i]>>y[i];
    }

    rep(i,x.size()-1){
      computex((y[i]-y[i+1])/(x[i]-x[i+1]),x[i],y[i],y[i]);
    }
    makegraph(n,x,y,all);
    rep(i,all.size())edge[i].clear();
    makeedge(all);
    

    printf("%.10lf\n",dijkstra(all));

  //    rep(i,all.size()){
  //      cout << all[i].x <<" " << all[i].y << endl;
  //    }
  }
  return false;
}

Measured memory_bytes: 2384