HDU 4063 Aircraft(计算几何)(The 36th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest)

题目链接: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 }
View Code

 

下面是用了一部分解析几何的方法,比上面的还要快……

 

代码(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 }
View Code

 

posted @ 2014-08-30 18:42  Oyking  阅读(264)  评论(0编辑  收藏  举报