几何加简单最短路。
题意是给出若干圆的圆心以及半径,求出从给出的起点到终点的最短路径的长度,可以移动的区域是圆覆盖到的任意一个位置。
做法是这样的,对圆两两求交点,用这些得到的交点以及起点和终点作为我们要构造的图的顶点。因为我们要的是最短路径,所以如果我们要从一个区域穿越到另一区域的时候,必然是经过这些交点的。然后我们可以对这些交点两两判断是否能够相互到达。这个判断才是这道题的关键。判断的方法可以有几种,我想到的一是先求出直线与所有圆的交点,排序以后判断所有的圆能否覆盖掉这条线段;而我的是另一种方法,就是用一个队列,将还没有被覆盖的线段存在队列里,每次跟圆相交判断线段是否仍未被覆盖。
最后来一个单源最短路就搞掂了!
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #include <vector> 7 #include <queue> 8 9 using namespace std; 10 11 const double EPS = 1e-10; 12 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 13 struct Point { 14 double x, y; 15 Point() {} 16 Point(double x, double y) : x(x), y(y) {} 17 bool operator < (Point a) const { return sgn(x - a.x) < 0 || sgn(x - a.x) == 0 && y < a.y;} 18 bool operator <= (Point a) const { return (sgn(x - a.x) < 0 || sgn(x - a.x) == 0 && sgn(y - a.y) < 0) || (sgn(x - a.x) == 0 && sgn(y - a.y) == 0);} 19 bool operator == (Point a) const { return sgn(x - a.x) == 0 && sgn(y - a.y) == 0;} 20 void print() { cout << x << '~' << y << endl;} 21 } ; 22 template <class T> T sqr(T x) { return x * x;} 23 typedef Point Vec; 24 Vec operator + (Vec a, Vec b) { return Vec(a.x + b.x, a.y + b.y);} 25 Vec operator - (Vec a, Vec b) { return Vec(a.x - b.x, a.y - b.y);} 26 Vec operator * (Vec a, double p) { return Vec(a.x * p, a.y * p);} 27 Vec operator / (Vec a, double p) { return Vec(a.x / p, a.y / p);} 28 29 inline double dotDet(Vec a, Vec b) { return a.x * b.x + a.y * b.y;} 30 inline double dotDet(Point o, Point a, Point b) { return dotDet(a - o, b - o);} 31 inline double crossDet(Vec a, Vec b) { return a.x * b.y - a.y * b.x;} 32 inline double crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);} 33 inline double vecLen(Vec x) { return sqrt(dotDet(x, x));} 34 inline double angle(Vec v) { return atan2(v.y, v.x);} 35 inline double angle(Vec a, Vec b) { return acos(dotDet(a, b) / vecLen(a) / vecLen(b));} 36 inline Vec vecUnit(Vec x) { return x / vecLen(x);} 37 inline Vec rotate(Vec x, double rad) { return Vec(x.x * cos(rad) - x.y * sin(rad), x.x * sin(rad) + x.y * cos(rad));} 38 inline Vec normal(Vec x) { return Vec(-x.y, x.x) / vecLen(x);} 39 40 struct Line { 41 Point s, t; 42 Line() {} 43 Line(Point s, Point t) : s(s), t(t) {} 44 Vec vec() { return t - s;} 45 Point point(double x) { return s + vec() * x;} 46 } ; 47 typedef Line Seg; 48 49 inline bool onSeg(Point x, Point a, Point b) { return sgn(crossDet(a - x, b - x)) == 0 && sgn(dotDet(a - x, b - x)) < 0;} 50 inline bool onSeg(Point x, Seg s) { return onSeg(x, s.s, s.t);} 51 52 inline Point lineIntersect(Point P, Vec v, Point Q, Vec w) { return P + v * (crossDet(w, P - Q) / crossDet(v, w));} 53 inline Point lineIntersect(Line a, Line b) { return lineIntersect(a.s, a.vec(), b.s, b.vec());} 54 55 struct Circle { 56 Point c; 57 double r; 58 Circle() {} 59 Circle(Point c, double r) : c(c), r(r) {} 60 Point point(double a) { return Point(c.x + cos(a) * r, c.y + sin(a) * r);} 61 } ; 62 int lineCircleIntersect(Line L, Circle C, vector<Point> &sol) { 63 Vec nor = normal(L.vec()); 64 Point mid = lineIntersect(C.c, nor, L.s, L.vec()); 65 double len = sqr(C.r) - sqr(vecLen(C.c - mid)); 66 if (sgn(len) < 0) return 0; 67 if (sgn(len) == 0) { sol.push_back(mid); return 1;} 68 Vec dis = vecUnit(L.vec()); 69 len = sqrt(len); 70 sol.push_back(mid + dis * len); 71 sol.push_back(mid - dis * len); 72 return 2; 73 } 74 75 int circleCircleIntersect(Circle C1, Circle C2, vector<Point> &sol) { 76 double d = vecLen(C1.c - C2.c); 77 if (sgn(d) == 0) { 78 if (sgn(C1.r - C2.r) == 0) return -1; 79 return -3 + (C1.r > C2.r); 80 } 81 if (sgn(C1.r + C2.r - d) < 0) return 0; 82 if (sgn(fabs(C1.r - C2.r) - d) > 0) return -3 + (C1.r > C2.r); 83 double a = angle(C2.c - C1.c); 84 double da = acos((sqr(C1.r) + sqr(d) - sqr(C2.r)) / (2.0 * C1.r * d)); 85 Point p1 = C1.point(a - da), p2 = C1.point(a + da); 86 sol.push_back(p1); 87 // p1.print(); 88 if (p1 == p2) return 1; 89 sol.push_back(p2); 90 // p2.print(); 91 return 2; 92 } 93 94 inline bool ptInCircle(Point p, Circle c) { return sgn(vecLen(c.c - p) - c.r) <= 0;} 95 96 const int N = 33; 97 Circle dev[N]; 98 vector<Point> vex; 99 int sid, tid; 100 double mat[N * N][N * N]; 101 102 Seg qseg[N * N]; 103 104 double cal(int pi, int pj, int n) { 105 // queue<Seg> seg; 106 vector<Point> ip; 107 int qh, qt; 108 qh = qt = 0; 109 // while (!seg.empty()) seg.pop(); 110 if (vex[pj] < vex[pi]) swap(pi, pj); 111 Seg L = Seg(vex[pi], vex[pj]); 112 // seg.push(L); 113 qseg[qt++] = L; 114 for (int i = 0; i < n; i++) { 115 // int sz = seg.size(); 116 int sz = qt - qh; 117 for (int j = 0; j < sz; j++) { 118 // Seg tmp = seg.front(); 119 // seg.pop(); 120 Seg tmp = qseg[qh++]; 121 // if (pi == 0 && pj == 2) { 122 // tmp.s.print(); 123 // tmp.t.print(); 124 // puts("tmp"); 125 // } 126 ip.clear(); 127 if (lineCircleIntersect(L, dev[i], ip) == 2) { 128 if (ip[1] < ip[0]) swap(ip[0], ip[1]); 129 // if (pi == 0 && pj == 4) { 130 // ip[0].print(); 131 // ip[1].print(); 132 // puts("ip"); 133 // } 134 if (ip[1] <= tmp.s || tmp.t <= ip[0]) 135 // seg.push(tmp); 136 qseg[qt++] = tmp; 137 else if (tmp.s <= ip[0] && ip[1] <= tmp.t) { 138 if (vecLen(tmp.s - ip[0]) > EPS) 139 // seg.push(Seg(tmp.s, ip[0])); 140 qseg[qt++] = Seg(tmp.s, ip[0]); 141 if (vecLen(tmp.t - ip[1]) > EPS) 142 // seg.push(Seg(ip[1], tmp.t)); 143 qseg[qt++] = Seg(ip[1], tmp.t); 144 } else if (tmp.s < ip[0] && ip[0] <= tmp.t && sgn(vecLen(tmp.s - ip[0]))) 145 // seg.push(Seg(tmp.s, ip[0])); 146 qseg[qt++] = Seg(tmp.s, ip[0]); 147 else if (tmp.s <= ip[1] && ip[1] < tmp.t && sgn(vecLen(ip[1] - tmp.t))) 148 // seg.push(Seg(ip[1], tmp.t)); 149 qseg[qt++] = Seg(ip[1], tmp.t); 150 } else 151 // seg.push(tmp); 152 qseg[qt++] = tmp; 153 } 154 // if (seg.size() == 0) 155 if (qh == qt) 156 return vecLen(vex[pi] - vex[pj]); 157 } 158 return -1.0; 159 } 160 161 void PRE(int n) { 162 vex.clear(); 163 for (int i = 0; i < n; i++) { 164 cin >> dev[i].c.x >> dev[i].c.y >> dev[i].r; 165 // vex.push_back(dev[i].c); 166 } 167 vex.push_back(dev[0].c); 168 vex.push_back(dev[n - 1].c); 169 Point ps = dev[0].c, pt = dev[n - 1].c; 170 for (int i = 0; i < n; i++) { 171 for (int j = 0; j < i; j++) { 172 // cout << i << " = = " << j << endl; 173 circleCircleIntersect(dev[i], dev[j], vex); 174 } 175 } 176 sort(vex.begin(), vex.end()); 177 int t = (int) (unique(vex.begin(), vex.end()) - vex.begin()); 178 while (vex.size() > t) vex.pop_back(); 179 // cout << "size " << vex.size() << endl; 180 for (int i = 0, sz = vex.size(); i < sz; i++) { 181 if (vex[i] == ps) sid = i; 182 if (vex[i] == pt) tid = i; 183 for (int j = 0; j <= i; j++) { 184 if (i == j) mat[i][j] = 0.0; 185 else mat[i][j] = mat[j][i] = cal(i, j, n); 186 } 187 } 188 // cout << sid << ' ' << tid << endl; 189 // for (int i = 0, sz = vex.size(); i < sz; i++) { 190 // vex[i].print(); 191 // for (int j = 0; j < sz; j++) printf("%7.4f ", mat[i][j]); 192 // cout << endl; 193 // } 194 } 195 196 const double FINF = 1e100; 197 double dis[N * N]; 198 int q[N * N << 1]; 199 double spfa() { 200 int sz = vex.size(); 201 // queue<int> Q; 202 // while (!Q.empty()) Q.pop(); 203 int qh, qt; 204 qh = qt = 0; 205 for (int i = 0; i < sz; i++) dis[i] = FINF; 206 dis[sid] = 0.0; 207 // Q.push(sid); 208 q[qt++] = sid; 209 // while (!Q.empty()) { 210 while (qh < qt) { 211 // int cur = Q.front(); 212 // Q.pop(); 213 int cur = q[qh++]; 214 for (int i = 0; i < sz; i++) { 215 if (mat[cur][i] < 0) continue; 216 if (dis[i] > dis[cur] + mat[cur][i]) { 217 dis[i] = dis[cur] + mat[cur][i]; 218 // Q.push(i); 219 q[qt++] = i; 220 } 221 } 222 } 223 // for (int i = 0; i < sz; i++) cout << dis[i] << ' '; cout << endl; 224 return dis[tid]; 225 } 226 227 int main() { 228 // freopen("in", "r", stdin); 229 // freopen("out", "w", stdout); 230 int T, n; 231 cin >> T; 232 for (int cas = 1; cas <= T; cas++) { 233 cin >> n; 234 PRE(n); 235 printf("Case %d: ", cas); 236 double ans = spfa(); 237 if (ans < FINF) printf("%.4f ", ans); 238 else puts("No such path."); 239 } 240 return 0; 241 }
附加自己出的数据:
1 8 2 2 3 0 0 1 4 2 0 1 5 2 6 0 0 1 7 4 1 2 8 3 9 -3 0 2 10 0 2 2 11 3 0 2 12 3 13 -3 0 2 14 0 3 3 15 3 0 2 16 6 17 -6 0 2 18 -3 0 2 19 0 3 3 20 3 0 2 21 7 0 2 22 0 8 2 23 10 24 -6 0 2 25 -3 0 2 26 0 3 3 27 3 0 2 28 7 0 2 29 0 8 2 30 -4 8 2 31 -8 8 2 32 -7 2 2 33 -8 4 2 34 3 35 0 10 7 36 -1 -1 100 37 10 0 7 38 3 39 -3 0 2 40 0 3 3 41 3 0 2
——written by Lyon