Language: C++

#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

typedef pair<double,double> pdd;

const double EPS=1e-9;

int n,x[100],y[100];

struct Pos{
	double a,b;
	Pos(double A,double B):a(A),b(B){}
	bool operator<(const Pos &p)const{
		if(abs(a-p.a)>EPS) return a<p.a;
		if(abs(b-p.b)>EPS) return b<p.b;
		return false;
	}
};

vector<Pos> findNextPos(const Pos &p){
	vector<int> ca,cb;
	rep(i,n-1){
		if(x[i]-EPS<p.a && p.a<x[i+1]+EPS) ca.push_back(i);
		if(x[i]-EPS<p.b && p.b<x[i+1]+EPS) cb.push_back(i);
	}

// rep(i,ca.size()) printf("ca[%d] = %d\n",i,ca[i]);
// rep(i,cb.size()) printf("cb[%d] = %d\n",i,cb[i]);
	vector<Pos> res;
	rep(i,ca.size()) rep(j,cb.size()) {
		int i1=ca[i],i2=ca[i]+1,j1=cb[j],j2=cb[j]+1;
		double yy,x1,x2;

		if(y[i1]==y[i2] || y[j1]==y[j2]){
			if(y[i1]==y[i2]){
				res.push_back(Pos(x[i1],p.b));
				res.push_back(Pos(x[i2],p.b));
			}
			if(y[j1]==y[j2]){
				res.push_back(Pos(p.a,x[j1]));
				res.push_back(Pos(p.a,x[j2]));
			}
		}
		else{
			yy=min(max(y[i1],y[i2]),max(y[j1],y[j2]));
			x1=(double)(x[i2]-x[i1])/(y[i2]-y[i1])*(yy-y[i1])+x[i1];
			x2=(double)(x[j2]-x[j1])/(y[j2]-y[j1])*(yy-y[j1])+x[j1];
			res.push_back(Pos(x1,x2));

			yy=max(min(y[i1],y[i2]),min(y[j1],y[j2]));
			x1=(double)(x[i2]-x[i1])/(y[i2]-y[i1])*(yy-y[i1])+x[i1];
			x2=(double)(x[j2]-x[j1])/(y[j2]-y[j1])*(yy-y[j1])+x[j1];
			res.push_back(Pos(x1,x2));
		}
	}

	return res;
}

inline double height(double xx){
	rep(i,n-1) if(x[i]-EPS<xx && xx<x[i+1]+EPS) {
		return (double)(y[i+1]-y[i])/(x[i+1]-x[i])*(xx-x[i])+y[i];
	}
	assert(0);
}

inline double calcDistance(const Pos &p,const Pos &q){
	double hpa=height(p.a),hpb=height(p.b),
		   hqa=height(q.a),hqb=height(q.b);
	return sqrt((p.a-q.a)*(p.a-q.a)+(hpa-hqa)*(hpa-hqa))
		  +sqrt((p.b-q.b)*(p.b-q.b)+(hpb-hqb)*(hpb-hqb));
}

double solve(){
	map<Pos,double> d;
	d[Pos(0,x[n-1])]=0;

	priority_queue< pair<double,Pos> > pq;
	pq.push(make_pair(0,Pos(0,x[n-1])));
	while(!pq.empty()){
		double cost=-pq.top().first;
		Pos p=pq.top().second; pq.pop();

		if(d[p]+EPS<cost) continue;
// printf("now : %2.3f %2.3f\n",p.a,p.b);
		if(abs(p.a-p.b)<EPS) return cost;

		vector<Pos> next=findNextPos(p);
// rep(i,next.size()){
	// printf(" next[%d] = %2.3f %2.3f\n",i,next[i].a,next[i].b);
// }
		rep(i,next.size()){
			double cost2=calcDistance(p,next[i]);
// if(d.count(next[i])) printf("  %.3f < %.3f\n",cost+cost2,d[next[i]]);
// else printf(" nothing\n");
			if(d.count(next[i])==0 || cost+cost2+EPS<d[next[i]]){
// printf("  push %2.3f %2.3f\n",next[i].a,next[i].b);
				d[next[i]]=cost+cost2;
				pq.push(make_pair(-(cost+cost2),next[i]));
			}
		}
	}
	assert(0);
}

int main(){
	for(;scanf("%d",&n),n;){
		rep(i,n) scanf("%d%d",x+i,y+i);

		printf("%.15f\n",solve());
	}

	return 0;
}

Compiler output:
a.cc: In function 'double height(double)':
a.cc:71:9: error: 'assert' was not declared in this scope
   71 |         assert(0);
      |         ^~~~~~
a.cc:5:1: note: 'assert' is defined in header '<cassert>'; this is probably fixable by adding '#include <cassert>'
    4 | #include<cstdio>
  +++ |+#include <cassert>
    5 | #include<vector>
a.cc: In function 'double solve()':
a.cc:110:9: error: 'assert' was not declared in this scope
  110 |         assert(0);
      |         ^~~~~~
a.cc:110:9: note: 'assert' is defined in header '<cassert>'; this is probably fixable by adding '#include <cassert>'
a.cc:111:1: warning: control reaches end of non-void function [-Wreturn-type]
  111 | }
      | ^
a.cc: In function 'double height(double)':
a.cc:72:1: warning: control reaches end of non-void function [-Wreturn-type]
   72 | }
      | ^