解法
2つの円の交点を通る線分に交わっているか確かめながら、Dijkstraした。
ソース
#include<complex> #include<algorithm> #include<vector> #include<map> #include<iomanip> #include<iostream> #include<queue> using namespace std; #define fr first #define sc second struct line: public vector< complex<double> >{ line(){}; line( const complex<double>& a, const complex<double>& b){ push_back(a); push_back(b); } }; struct circle { complex<double> p; double r; circle():p(0,0),r(0){}; circle(const complex<double> &p, double r) : p(p),r(r){} }; typedef complex < double > P; typedef line L; typedef pair < P, P > Ls; typedef vector< P > G; typedef vector< P > Ps; typedef vector< L > LLL; typedef circle C; const double EPS = 1e-9; const double INF = 1e8; bool eq(P,P); //点:点 一緒か double cross(P,P); //外積 double dot(P,P); //内積 int ccw(P,P,P); //3点の位置関係 bool parallel(L,L); // 直線//直線 bool orthogonal(L,L); //直線⊥直線 bool intersect(L,L); //線分:線分交差 bool intersect(L,P); //線分:点交差 bool intersect(Ls,Ls); //直線:直線交差 bool intersect(Ls,L); //直線:線分交差 bool intersect(Ls,P); //直線:点交差 int intersect(C,L); //円:線分交点数 double distance(L,L); //線分:線分の距離 double distance(L,P); //線分:点の距離 double distance(P,P); //点:点の距離 double distance(Ls,P); //直線:点距離 double distance(Ls,Ls); //直線:直線距離 double distance(Ls,L); //直線:線分距離 P crosspoint(L,L); //線分:線分交点計算 L crosspoint(C,Ls); //円:直線交点計算 L crosspoint(C,L); //円:線分交点計算 Ps crosspoint(C,C); //円:円交点計算 int contains(G,P); //GがPが包容か double area2(G); //Gの面積 bool isconvex(G); //凸性判定 Ps convex(G); //凸包 namespace std { bool operator < (const P& a, const P& b) { return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b); } } L llcomb(Ls a){ L line( a.fr, a.sc); return line; } Ls llrcomb(L a){ Ls line( a[0], a[1]); return line; } bool eq( P a, P b){ return abs( a - b) < EPS; } double cross( P a, P b){ return imag( conj(a) * b); } double dot( P a, P b){ return real( conj(a) * b); } P projection( L l, P p) { double t = dot( p - l[0], l[0] - l[1]) / norm( l[0] - l[1]); return l[0] + t * ( l[0] - l[1]); } int ccw( P a, P b, P c){ b -= a, c -= a; if(cross(b,c) > EPS) return 1; // a → b で 時計方向におれて c if(cross(b,c) < -EPS) return -1; // a → b で 反時計方向におれて c if(dot(b,c) < -EPS) return 2; // c -- a -- b if(norm(b) < norm(c) - EPS) return -2; // a -- b -- c return 0; // a -- c -- b } bool intersect( L a, L b){ return ccw( a[0], a[1], b[0]) * ccw( a[0], a[1], b[1]) <= 0 && ccw( b[0], b[1], a[0]) * ccw( b[0], b[1], a[1]) <= 0; } bool intersect( L a, P p){ return abs( a[0] - p) + abs( a[1] - p) - abs( a[1] - a[0]) < EPS; } bool intersect( Ls l, Ls m) { return abs(cross(l.sc-l.fr, m.sc-m.fr)) > EPS || abs(cross(l.sc-l.fr, m.fr-l.fr)) < EPS; } bool intersect(Ls l, L s) { return cross( l.sc - l.fr, s[0] - l.fr) * // s[0] is left of l cross( l.sc - l.fr, s[1] - l.fr) < EPS; // s[1] is right of l } bool intersect(Ls l, P p) { return abs( cross( l.sc - p, l.fr - p)) < EPS; } int intersect( C c, L l){ if( norm( projection( l, c.p) - c.p) - c.r * c.r > EPS) return 0; const double d1 = abs( c.p - l[0]), d2 = abs( c.p - l[1]); if( d1 < c.r + EPS && d2 < c.r + EPS) return 0; if( d1 < c.r - EPS && d2 > c.r + EPS || d1 > c.r + EPS && d2 < c.r - EPS ) return 1; const P h = projection(l, c.p); if( dot( l[0] - h, l[1] - h) < 0) return 2; return 0; } double distance( L s, P p){ P r = projection(s, p); if ( intersect( s, r)) return abs( r - p); return min( abs( s[0] - p), abs( s[1] - p)); } double distance( L a, L b){ if(intersect( a, b)) return 0; return min( min( distance( a, b[0]), distance( a, b[1])), min( distance( b, a[0]), distance( b, a[1]))); } double distance( Ls l, P p) { return abs(p - projection( llcomb(l), p)); } double distance( Ls l, Ls m) { return intersect(llcomb(l), llcomb(m)) ? 0 : distance(llcomb(l), m.fr); } double distance( Ls l, L s) { if (intersect(l, s)) return 0; return min(distance(l, s[0]), distance(l, s[1])); } double distance( P a, P b){ return abs( a - b); } bool parallel( L a, L b){ return abs( cross( a[1] - a[0], b[1] - b[0])) < EPS; } bool orthogonal( L a, L b){ return dot( a[0] - a[1], b[0] - b[1]) < EPS; } #define curr(P,i) P[i] #define next(P,i) P[(i+1)%P.size()] #define prev(P, i) P[(i+P.size()-1) % P.size()] enum { OUT, ON, IN }; int conteins(G Q, P p){ bool in = false; for(int i = 0 ; i < Q.size() ; i++ ){ P a = curr(Q,i) - p, b = next(Q,i) - p; if(imag(a) > imag(b)) swap(a,b); if(imag(a) <= 0 && 0 < imag(b) && cross(a,b) < 0) in = !in; if(cross(a,b) == 0 && dot(a,b) <= 0) return ON; } return in ? IN : OUT; } double area2(G p){ double A = 0; for (int i = 0; i < p.size(); ++i){ A += cross(curr(p, i), next(p, i)); } return A; } bool isconvex(G p) { for (int i = 0; i < p.size(); ++i){ if (ccw(prev(p, i), curr(p, i), next(p, i)) > 0) return false; } return true; } Ps convex(Ps ps) { //n>=3 int k = 0; sort(ps.begin(), ps.end()); Ps ch(2 * ps.size()); for (int i = 0; i < ps.size(); ch[k++] = ps[i++]){ while (k >= 2 and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k; } for (int i = ps.size()-2, t = k+1; i >= 0; ch[k++] = ps[i--]){ while (k >= t and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k; } ch.resize(k-1); return ch; } P crosspoint(L l, L m) { double A = cross(l[1] - l[0], m[1] - m[0]); double B = cross(l[1] - l[0], l[1] - m[0]); if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line return m[0] + B / A * (m[1] - m[0]); } L crosspoint( C c, Ls l) { const P hp = projection( llcomb(l), c.p), h = hp - c.p; const double d2 = norm(h); P v = sqrt( c.r * c.r - d2) * ( l.sc - l.fr) / abs( l.sc - l.fr); return L(hp - v, hp + v); } L crosspoint( C c, L l) { if(intersect(c, l) == 2) return crosspoint(c, llrcomb(l)); L ret = crosspoint(c, llrcomb(l)); if(dot(l[0] - ret[0], l[1] - ret[0]) < 0) ret[1] = ret[0]; else ret[0] = ret[1]; return ret; } Ps crosspoint(C c1, C c2){ double d = abs(c1.p - c2.p); double s = (c1.r + c2.r + d) / 2; double S = sqrt( s * ( s - c1.r) * ( s - c2.r) * ( s - d)); double h = 2 * S / d; P v = ( c2.p - c1.p) / ( abs( c2.p - c1.p)); double m = sqrt( c1.r * c1.r - h * h); Ps ret; ret.push_back( c1.p + m * v + h * v * P(0,1)); ret.push_back( c1.p + m * v - h * v * P(0,1)); return ret; } struct dC{ double cost; P pos; int nowi,nowj; bool operator < (const dC &left) const { return cost > left.cost; } }; L make_2_cross(C c1, C c2){ Ps a(crosspoint( c1, c2)); return L( a[0], a[1]); } int main(){ C prev, now; int n; while(cin >> n , n){ LLL ls; cin >> prev.p.real() >> prev.p.imag() >> prev.r; ls.push_back( L( prev.p, prev.p)); for(int i = 1 ; i < n ; i++ ){ cin >> now.p.real() >> now.p.imag() >> now.r; ls.push_back( make_2_cross( prev, now)); prev = now; } ls.push_back( L( prev.p, prev.p)); // G priority_queue< dC > que; que.push((dC){ 0, ls[0][0], 0, 0}); bool used[101][2] = {{}}; double ret = INF; while(!que.empty()){ dC p = que.top(); que.pop(); if(p.nowj == n){ ret = p.cost; break; } if(used[p.nowj][p.nowi]++) continue; for(int i = 0 ; i < 2 ; i++ ){ for(int j = p.nowj + 1 ; j <= n ; j++ ){ L l = L( p.pos, ls[j][i]); bool flag = true; for(int k = j - 1 ; k > p.nowj ; k-- ){ if(!intersect( l, ls[k])){ flag = false; break; } } if(flag) que.push( (dC){ abs( l[0] - l[1]) + p.cost, l[1], i, j}); } } } cout << fixed << setprecision(7) << ret << endl; } }
0 件のコメント:
コメントを投稿