HDU 4063 Aircraft(计算几何)

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

时间: 2024-11-04 18:33:43

HDU 4063 Aircraft(计算几何)的相关文章

hdu 4063 Aircraft 计算几何+最短路

易知最短路一定是以圆心或者两圆交点作为中间点到达的.所以把这些点拿出来建图跑最短路就够了. 现在的问题就是,给定两个点,能否连边 add(a,b,dist(a,b)) 题目要求,ab线段必须完全在圆上,所以可以求出ab线段和所有圆的所有交点,对于任意相邻两个交点,它们必处于同一个圆内,否则不可达.点的编号用map就够了(一开始我以为double有精度问题无法map,用两个longlong保存然后乘上1000000000,后来发现没问题,应该是这题都是整点,精度要求不高的原因吧) #include

HDU 4063 Aircraft --几何,最短路

题意: 给一些圆,要求从第一个圆的圆心走到最后一个圆的圆心,中间路径必须在某个圆内,求最短路径的长度. 解法: 易知要保持在圆内且路径最短,走两圆相交的点能使路径尽量短,所以我们找出所有的两圆相交的点,再加上起点和终点,放到一个容器中,去重后,判断每两点之间的线段是否都在圆内,如果是则建边,建完所有的边后跑一个SPFA即可得出最短路. 代码: #include <iostream> #include <cstdio> #include <cstring> #includ

HDU 4063 线段与圆相交+最短路

Aircraft Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 980    Accepted Submission(s): 228 Problem Description You are playing a flying game. In the game, player controls an aircraft in a 2D-

hdu 1086(计算几何入门题——计算线段交点个数)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086 You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7167    Accepted Submission(s): 3480 Problem Description Ma

HDU 1174 爆头 (计算几何)

爆头 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1628    Accepted Submission(s): 678 Problem Description gameboy是一个CS高手,他最喜欢的就是扮演警察,手持M4爆土匪的头.也许这里有人没玩过CS,有必要介绍一下“爆头”这个术语:所谓爆头,就是子弹直接命中对方的头部,以秒杀

hdu 4643(计算几何)

题意:容易理解 分析:切换的地点为两个基站所在直线的中垂线与两座城市所在直线的交点. 代码实现: #include <cstdio> #include <cmath> #include <algorithm> #define maxn 60 #define eps 1e-7 using namespace std; int dcmp(double x) //控制精度 { if(fabs(x)<eps) return 0; else return x<0?-1

2017多校第6场 HDU 6097 Mindis 计算几何,圆的反演

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6097 题意:有一个圆心在原点的圆,给定圆的半径,给定P.Q两点坐标(PO=QO,P.Q不在圆外),取圆上一点D,求PD+QD的最小值. 解法:圆的反演. 很不幸不总是中垂线上的点取到最小值,考虑点在圆上的极端情况. 做P点关于圆的反演点P',OPD与ODP'相似,相似比是|OP| : r. Q点同理. 极小化PD+QD可以转化为极小化P'D+Q'D. 当P'Q'与圆有交点时,答案为两点距离,否则最优

HDU 5365(计算几何)

Run Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 101    Accepted Submission(s): 43 Problem Description AFA is a girl who like runing.Today,he download an app about runing .The app can record

HDU 4998 Rotate 计算几何 2014 ACM/ICPC Asia Regional Anshan Online

题意: 有一个平面放在一个二维坐标轴上 给定n个操作 (x,y) p 表示把平面绕着(x,y) 逆时针转p弧度. 最后的结果相当于平面绕着(X, Y) 逆时针旋转了P弧度. 求:X,Y,P 思路: 任取一个三角形ABC,然后根据n个操作得到A'B'C', 然后求外心. 旋转的角度就是相加..==为啥我也不大清楚,不是本弱写的. #include <cstdio> #include <algorithm> #include <iostream> #include <