题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4063
Description
You are playing a flying game.
In the game, player controls an aircraft in a 2D-space.
The mission is to drive the craft from starting point to terminal point.
The craft needs wireless signal to move.
A number of devices are placed in the 2D-space, spreading signal.
For a device Di, it has a signal radius -- Ri.
When the distance between the craft and Di is shorter or equal to Ri, it(the craft) gets Di‘s wireless signal.
Now you need to tell me the shortest path from starting point to terminal point.
Input
The first line of the input file is a single integer T.
The rest of the test file contains T blocks.
Each block starts with an integer n, followed by n devices given as (xi, yi, Ri).
(xi, yi) is position of Di, and Ri is the radius of its signal range.
The first point is the starting point.
The last point is the terminal point.
T <= 25;
2 <= n <= 20 for most cases;
20 < n <= 25 for several cases, completely random generated.
-1000 <= xi, yi <= 1000 , 1 <= ri <= 1000.
All are integers.
Output
For each case, Output "No such path." if the craft can‘t get to the terminal point.
Otherwise, output a float number, correct the result to 4 decimal places.(as shown in the sample output)
题目大意&题解:http://blog.csdn.net/zxy_snow/article/details/6849550
PS:首位共点的时候一直输出No such path没发现调了半天……
下面是用计算几何的方法,不知为何G++一直TLE(难道是我写错了?),可能是因为加入了大量的函数运算然后没有被优化……
顺便贴个模板
代码(C++ 750MS):
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 typedef long long LL; 8 9 const int MAXN = 22; 10 const int MAXV = MAXN * MAXN * 2; 11 const int MAXE = MAXV * MAXV; 12 const double EPS = 1e-6; 13 const double INF = 1e100; 14 15 inline double sqr(double x) { 16 return x * x; 17 } 18 19 inline int sgn(double x) { 20 return (x > EPS) - (x < -EPS); 21 } 22 23 struct Point { 24 double x, y; 25 Point() {} 26 Point(double x, double y): x(x), y(y) {} 27 void read() { 28 scanf("%lf%lf", &x, &y); 29 } 30 bool operator < (const Point &rhs) const { 31 if(sgn(x - rhs.x) != 0) return x < rhs.x; 32 return sgn(y - rhs.y) < 0; 33 } 34 bool operator == (const Point &rhs) const { 35 return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0; 36 } 37 Point operator + (const Point &rhs) const { 38 return Point(x + rhs.x, y + rhs.y); 39 } 40 Point operator - (const Point &rhs) const { 41 return Point(x - rhs.x, y - rhs.y); 42 } 43 double operator * (const Point &rhs) const { 44 return x * rhs.x + y * rhs.y; 45 } 46 Point operator * (double d) const { 47 return Point(x * d, y * d); 48 } 49 Point operator / (double d) const { 50 return Point(x / d, y / d); 51 } 52 Point rotate() const { 53 return Point(-y, x); 54 } 55 double length() const { 56 return sqrt(*this * *this); 57 } 58 }; 59 60 double dist(const Point &a, const Point &b) { 61 return (a - b).length(); 62 } 63 64 double cross(const Point &a, const Point &b) { 65 return a.x * b.y - a.y * b.x; 66 } 67 68 double cross(const Point &o, const Point &a, const Point &b) { 69 return cross(a - o, b - o); 70 } 71 72 double Point_to_Line(const Point &p, const Point &st, const Point &ed) { 73 return fabs(cross(p, st, ed)) / dist(st, ed); 74 } 75 76 Point intersection(const Point &u1, const Point &u2, const Point &v1, const Point &v2) { 77 double t = cross(u1 - v1, v1 - v2) / cross(u1 - u2, v1 - v2); 78 return u1 + (u2 - u1) * t; 79 } 80 81 struct Circle { 82 Point c; 83 double r; 84 Circle() {} 85 Circle(Point c, double r): c(c), r(r) {} 86 void read() { 87 c.read(); 88 scanf("%lf", &r); 89 } 90 bool contain(const Circle &rhs) const { 91 return sgn(dist(c, rhs.c) + rhs.r - r) <= 0; 92 } 93 bool contain(const Point &p) const { 94 return sgn(dist(c, p) - r) <= 0; 95 } 96 bool intersect(const Circle &rhs) const { 97 return sgn(dist(c, rhs.c) - r - rhs.r) < 0; 98 } 99 bool tangency(const Circle &rhs) const { 100 return sgn(dist(c, rhs.c) - r - rhs.r) == 0; 101 } 102 }; 103 104 int intersection(const Circle &cir, const Point &st, const Point &ed, Point &p1, Point &p2) { 105 if(sgn(Point_to_Line(cir.c, st, ed) - cir.r) > 0) return 0; 106 Point p = cir.c + (ed - st).rotate(); 107 p = intersection(p, cir.c, st, ed); 108 double t = sqrt(sqr(cir.r) - sqr(dist(p, cir.c))) / dist(st, ed); 109 p1 = p + (ed - st) * t; 110 p2 = p - (ed - st) * t; 111 return 2 - (p1 == p2); 112 } 113 114 int intersection(const Circle &c1, const Circle &c2, Point &p1, Point &p2) { 115 if(c1.contain(c2) || c2.contain(c1)) return 0; 116 if(!c1.intersect(c2) && !c1.tangency(c2)) return 0; 117 double t = 0.5 * (1 + (sqr(c1.r) - sqr(c2.r)) / sqr(dist(c1.c, c2.c))); 118 Point u = c1.c + (c2.c - c1.c) * t, v = u + (c1.c - c2.c).rotate(); 119 return intersection(c1, u, v, p1, p2); 120 } 121 122 struct Graph { 123 int head[MAXV], ecnt; 124 int to[MAXE], next[MAXE]; 125 double cost[MAXE]; 126 int n, st, ed; 127 128 void init() { 129 memset(head, -1, sizeof(head)); 130 ecnt = 0; 131 } 132 133 void add_edge(int u, int v, double c) { 134 to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 135 to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++; 136 } 137 138 double dis[MAXV]; 139 bool vis[MAXV]; 140 141 double dijksrta(int st, int ed, int n) { 142 for(int i = 0; i < n; ++i) dis[i] = INF; 143 dis[st] = 0; 144 memset(vis, 0, sizeof(vis)); 145 while(true) { 146 int u = -1; double d = INF; 147 for(int i = 0; i < n; ++i) if(!vis[i]) 148 if(dis[i] < d) d = dis[i], u = i; 149 if(d == INF) break; 150 vis[u] = true; 151 for(int p = head[u]; ~p; p = next[p]) { 152 int &v = to[p]; 153 if(!vis[v]) dis[v] = min(dis[v], dis[u] + cost[p]); 154 } 155 } 156 return dis[ed]; 157 } 158 } G; 159 160 Circle cir[MAXN]; 161 int T, n; 162 163 Point list[MAXV]; 164 165 bool havePath(Point st, Point ed) { 166 if(ed < st) swap(st, ed); 167 if(st == ed) return true; 168 Point p1, p2; 169 int pcnt = 0; 170 list[pcnt++] = st; 171 list[pcnt++] = ed; 172 for(int i = 0; i < n; ++i) { 173 int c = intersection(cir[i], st, ed, p1, p2); 174 if(c >= 1) list[pcnt++] = p1; 175 if(c >= 2) list[pcnt++] = p2; 176 } 177 sort(list, list + pcnt); 178 for(int i = 0; i < pcnt; ++i) { 179 if(list[i] < st || list[i] == st) continue; 180 bool flag = false; 181 for(int j = 0; j < n && !flag; ++j) 182 if(cir[j].contain(list[i]) && cir[j].contain(list[i - 1])) flag = true; 183 if(!flag) return false; 184 if(list[i] == ed) break; 185 } 186 return true; 187 } 188 189 Point p[MAXV]; 190 int cnt; 191 192 double solve() { 193 Point p1, p2; 194 cnt = 0; 195 p[cnt++] = cir[0].c; p[cnt++] = cir[n - 1].c; 196 for(int i = 0; i < n; ++i) { 197 for(int j = i + 1; j < n; ++j) { 198 int c = intersection(cir[i], cir[j], p1, p2); 199 if(c >= 1) p[cnt++] = p1; 200 if(c >= 2) p[cnt++] = p2; 201 } 202 } 203 G.init(); 204 for(int i = 0; i < cnt; ++i) { 205 for(int j = i + 1; j < cnt; ++j) 206 if(havePath(p[i], p[j])) G.add_edge(i, j, dist(p[i], p[j])); 207 } 208 return G.dijksrta(0, 1, cnt); 209 } 210 211 int main() { 212 scanf("%d", &T); 213 for(int kase = 1; kase <= T; ++kase) { 214 scanf("%d", &n); 215 for(int i = 0; i < n; ++i) cir[i].read(); 216 double res = solve(); 217 if(res == INF) printf("Case %d: No such path.\n", kase); 218 else printf("Case %d: %.4f\n", kase, res); 219 } 220 }
下面是用了一部分解析几何的方法,比上面的还要快……
代码(G++ 437MS):
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #include <numeric> 7 using namespace std; 8 typedef long long LL; 9 10 const int MAXN = 44; 11 const int MAXV = MAXN * MAXN * 2; 12 const int MAXE = MAXV * MAXV; 13 const double EPS = 1e-12; 14 const double INF = 1e100; 15 16 inline double sqr(double x) { 17 return x * x; 18 } 19 20 inline int sgn(double x) { 21 return (x > EPS) - (x < -EPS); 22 } 23 24 struct Point { 25 double x, y; 26 Point() {} 27 Point(double x, double y): x(x), y(y) {} 28 void read() { 29 scanf("%lf%lf", &x, &y); 30 } 31 bool operator < (const Point &rhs) const { 32 if(sgn(x - rhs.x) != 0) return x < rhs.x; 33 return sgn(y - rhs.y) < 0; 34 } 35 bool operator == (const Point &rhs) const { 36 return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0; 37 } 38 Point operator + (const Point &rhs) const { 39 return Point(x + rhs.x, y + rhs.y); 40 } 41 Point operator - (const Point &rhs) const { 42 return Point(x - rhs.x, y - rhs.y); 43 } 44 double operator * (const Point &rhs) const { 45 return x * rhs.x + y * rhs.y; 46 } 47 Point operator * (double d) const { 48 return Point(x * d, y * d); 49 } 50 Point operator / (double d) const { 51 return Point(x / d, y / d); 52 } 53 Point rotate() const { 54 return Point(-y, x); 55 } 56 double length() const { 57 return sqrt(*this * *this); 58 } 59 }; 60 61 double dist(const Point &a, const Point &b) { 62 return (a - b).length(); 63 } 64 65 double cosIncludeAngle(const Point &a, const Point &b, const Point &o) { 66 Point p1 = a - o, p2 = b - o; 67 return (p1 * p2) / (p1.length() * p2.length()); 68 } 69 70 struct Circle { 71 Point c; 72 double r; 73 Circle() {} 74 Circle(Point c, double r): c(c), r(r) {} 75 void read() { 76 c.read(); 77 scanf("%lf", &r); 78 } 79 bool contain(const Circle &rhs) const { 80 return sgn(dist(c, rhs.c) + rhs.r - r) <= 0; 81 } 82 bool contain(const Point &p) const { 83 return sgn(dist(c, p) - r) <= 0; 84 } 85 bool intersect(const Circle &rhs) const { 86 return sgn(dist(c, rhs.c) - r - rhs.r) < 0; 87 } 88 bool tangency(const Circle &rhs) const { 89 return sgn(dist(c, rhs.c) - r - rhs.r) == 0; 90 } 91 }; 92 93 int intersection(const Point &st, const Point &ed, const Circle &cir, Point &p1, Point &p2) { 94 double angle = cosIncludeAngle(ed, cir.c, st); 95 if(isnan(angle)) { 96 Point v = (ed - st) / dist(st, ed); 97 p1 = cir.c + v * cir.r; 98 p2 = cir.c - v * cir.r; 99 return 1 + (cir.r > 0); 100 } 101 double B = dist(cir.c, st); 102 double a = 1, b = -2 * B * angle, c = sqr(B) - sqr(cir.r); 103 double delta = sqr(b) - 4 * a * c; 104 if(sgn(delta) < 0) return 0; 105 if(sgn(delta) == 0) delta = 0; 106 double x1 = (-b - sqrt(delta)) / (2 * a), x2 = (-b + sqrt(delta)) / (2 * a); 107 Point v = (ed - st) / dist(ed, st); 108 p1 = st + v * x1; 109 p2 = st + v * x2; 110 return 1 + sgn(delta); 111 } 112 113 int intersection(const Circle &c1, const Circle &c2, Point &p1, Point &p2) { 114 if(c1.contain(c2) || c2.contain(c1)) return 0; 115 if(!c1.intersect(c2) && !c1.tangency(c2)) return 0; 116 double d = dist(c1.c, c2.c); 117 double d1 = (sqr(c2.r) + sqr(d) - sqr(c1.r)) / 2 / d; 118 double d2 = sqrt(sqr(c2.r) - sqr(d1)); 119 Point v1 = c2.c + (c1.c - c2.c) / d * d1; 120 Point v2 = (c1.c - c2.c).rotate() / d; 121 p1 = v1 + v2 * d2; 122 p2 = v1 - v2 * d2; 123 return 2 - (p1 == p2); 124 } 125 126 struct Graph { 127 int head[MAXV], ecnt; 128 int to[MAXE], next[MAXE]; 129 double cost[MAXE]; 130 int n, st, ed; 131 132 void init() { 133 memset(head, -1, sizeof(head)); 134 ecnt = 0; 135 } 136 137 void add_edge(int u, int v, double c) { 138 to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 139 to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++; 140 } 141 142 double dis[MAXV]; 143 bool vis[MAXV]; 144 145 double dijksrta(int st, int ed, int n) { 146 for(int i = 0; i < n; ++i) dis[i] = INF; 147 dis[st] = 0; 148 memset(vis, 0, sizeof(vis)); 149 while(true) { 150 int u = -1; double d = INF; 151 for(int i = 0; i < n; ++i) if(!vis[i]) 152 if(dis[i] < d) d = dis[i], u = i; 153 if(d == INF) break; 154 vis[u] = true; 155 for(int p = head[u]; ~p; p = next[p]) { 156 int &v = to[p]; 157 if(!vis[v]) dis[v] = min(dis[v], dis[u] + cost[p]); 158 } 159 } 160 return dis[ed]; 161 } 162 } G; 163 164 Circle cir[MAXN]; 165 int T, n; 166 167 Point list[MAXV]; 168 169 bool havePath(Point st, Point ed) { 170 if(ed < st) swap(st, ed); 171 if(st == ed) return true; 172 Point p1, p2; 173 int pcnt = 0; 174 list[pcnt++] = st; 175 list[pcnt++] = ed; 176 for(int i = 0; i < n; ++i) { 177 int c = intersection(st, ed, cir[i], p1, p2); 178 if(c >= 1) list[pcnt++] = p1; 179 if(c >= 2) list[pcnt++] = p2; 180 } 181 sort(list, list + pcnt); 182 for(int i = 0; i < pcnt; ++i) { 183 if(list[i] < st || list[i] == st) continue; 184 bool flag = false; 185 //Point x = (list[i] + list[i - 1]) / 2; 186 for(int j = 0; j < n && !flag; ++j) 187 if(cir[j].contain(list[i]) && cir[j].contain(list[i - 1])) flag = true; 188 if(!flag) return false; 189 if(list[i] == ed) break; 190 } 191 return true; 192 } 193 194 Point p[MAXV]; 195 int cnt; 196 197 double solve() { 198 Point p1, p2; 199 cnt = 0; 200 p[cnt++] = cir[0].c; p[cnt++] = cir[n - 1].c; 201 for(int i = 0; i < n; ++i) { 202 for(int j = i + 1; j < n; ++j) { 203 int c = intersection(cir[i], cir[j], p1, p2); 204 if(c >= 1) p[cnt++] = p1; 205 if(c >= 2) p[cnt++] = p2; 206 } 207 } 208 G.init(); 209 for(int i = 0; i < cnt; ++i) { 210 for(int j = i + 1; j < cnt; ++j) 211 if(havePath(p[i], p[j])) G.add_edge(i, j, dist(p[i], p[j])); 212 } 213 return G.dijksrta(0, 1, cnt); 214 } 215 216 int main() { 217 scanf("%d", &T); 218 for(int kase = 1; kase <= T; ++kase) { 219 scanf("%d", &n); 220 for(int i = 0; i < n; ++i) cir[i].read(); 221 double res = solve(); 222 if(res == INF) printf("Case %d: No such path.\n", kase); 223 else printf("Case %d: %.4f\n", kase, res); 224 } 225 }