Language: C++

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <limits.h>
#include <float.h>
#include <queue>

#define eps 10e-5
#define INF 1e8
#define M INT_MAX
using namespace std;

struct P{
	double x;
	double y;

	P(){
		x=M; y=M;
	}

	P(const double &s , const double &e)
		{ x=s; y=e;}

	P operator - (const P &t) const
	{ return P(x-t.x , y-t.y); }

	P operator + (const P &t) const
	{ return P(x+t.x , y+t.y); }

	P operator * (const double &d) const
	{ return P(x*d , y*d); }

};

double dis(P t);

struct L{
	P p1,p2;

	L(){}

	L(const P &s , const P &e)
		{ p1=s; p2=e;}
	double ldis(){
		return dis(p1-p2);
	}
};

struct C{
	P a;
	double r;
	C(){}
	C(const P &s , const double &e)
		{ a=s; r=e;}
};

//距離を求める
double dis(P t){
	return sqrt(t.x*t.x+t.y*t.y);
}

//単位ベクトルを求める
P unit_vector(P t){
	double u=fabs(dis(t));
	return P(t.x/u , t.y/u);
}

//外積を求める a×b
double cross(P a,P b){
	return (a.x*b.y-a.y*b.x);
}

//線分交差判定
bool intersect_s(P a1 , P a2 , P b1 , P b2){
	return ( cross(a2-a1 , b1-a1)*cross(a2-a1 , b2-a1) < eps) &&
		   ( cross(b2-b1 , a1-b1)*cross(b2-b1 , a2-b1) < eps);
}




//点pを中心としてr(radian)回転		p(0,0)で原点を中心として回転
P rotate(P t , P p , double r){
	//double r=radians(angle);
	double ta=cos(r)*(t.x-p.x)-sin(r)*(t.y-p.y)+p.x;
	double tb=sin(r)*(t.x-p.x)+cos(r)*(t.y-p.y)+p.y;
	return P(ta , tb);
}

//応用
//２円 |x-a|=raと|x-b|=rbの交点計算
L interpoint_cc(C a , C b){
	double di=fabs(dis(a.a-b.a));
	if(di > a.r+b.r || di < fabs(a.r-b.r)) return L(P(0, 0), P(0, 0));
	double t=(a.r*a.r-b.r*b.r+di*di)/(di+di);
	double rd=acos(t/a.r);

	P dv=unit_vector(b.a-a.a);
	P g1=rotate(dv , P(0,0) , rd);
	P g2=rotate(dv , P(0,0) , -rd);
	return L(a.a+g1*a.r, a.a+g2*a.r);
}

class State{
public:
	double sum;
	int t,s;
	P cur;
	State(){}
	State(double c, int a, int b, P p):sum(c),t(a),s(b),cur(p){}
	bool operator < (const State &opp)const{
		return sum > opp.sum;
	}
};


double dp[101][2];
int v[101][2];
vector <L> Lines;

bool check(L l, int s, int t){
	for(;s<t;s++) if(!intersect_s(l.p1, l.p2, Lines[s].p1, Lines[s].p2))return 0;
	return 1;
}

main(){
	int i,j,n;

	while(cin>>n, n){
		priority_queue<State> S;
		memset(v, 0, sizeof(v));
		for(i=0;i<=100;i++) dp[i][0] = dp[i][1] = INF;
		Lines.clear();
		C Prev, Now;
		cin >> Now.a.x >> Now.a.y >> Now.r;
		P Start = Now.a;
		Lines.push_back(L(Start, Start));
		for(i=1;i<n;i++){
			Prev = Now;
			cin >> Now.a.x >> Now.a.y >> Now.r;
			Lines.push_back(interpoint_cc(Now, Prev));
		}
		Lines.push_back(L(Now.a, Now.a));
		S.push(State(0, 0, 0, Start));
		while(!S.empty()){
			State t = S.top();S.pop();
			if(v[t.t][t.s]) continue;
			v[t.t][t.s] = 1;
			if(t.t == n) break;
			for(i=t.t+1;i<=n;i++){
				for(j=0;j<2;j++){
					if(v[i][j]) continue;
					L l = L(t.cur, (j?Lines[i].p2:Lines[i].p1));
					if(!check(l, t.t+1, i)) continue;
					if(dp[i][j] < l.ldis() + t.sum) continue;
					dp[i][j] = l.ldis() + t.sum;
					S.push(State(dp[i][j], i, j, l.p2));
				}
			}
		}
		printf("%.4lf\n", dp[n][0]);
	}
}

Compiler output:
a.cc:127:1: warning: ISO C++ forbids declaration of 'main' with no type [-Wreturn-type]
  127 | main(){
      | ^~~~
a.cc: In function 'int main()':
a.cc:132:17: error: 'memset' was not declared in this scope
  132 |                 memset(v, 0, sizeof(v));
      |                 ^~~~~~
a.cc:8:1: note: 'memset' is defined in header '<cstring>'; this is probably fixable by adding '#include <cstring>'
    7 | #include <queue>
  +++ |+#include <cstring>
    8 |