
题目链接: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.
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.
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)
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):
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXV = MAXN * MAXN * ;
const int MAXE = MAXV * MAXV;
const double EPS = 1e-;
const double INF = 1e100; inline double sqr(double x) {
return x * x;
} inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} struct Point {
double x, y;
Point() {}
Point(double x, double y): x(x), y(y) {}
void read() {
scanf("%lf%lf", &x, &y);
}
bool operator < (const Point &rhs) const {
if(sgn(x - rhs.x) != ) return x < rhs.x;
return sgn(y - rhs.y) < ;
}
bool operator == (const Point &rhs) const {
return sgn(x - rhs.x) == && sgn(y - rhs.y) == ;
}
Point operator + (const Point &rhs) const {
return Point(x + rhs.x, y + rhs.y);
}
Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
double operator * (const Point &rhs) const {
return x * rhs.x + y * rhs.y;
}
Point operator * (double d) const {
return Point(x * d, y * d);
}
Point operator / (double d) const {
return Point(x / d, y / d);
}
Point rotate() const {
return Point(-y, x);
}
double length() const {
return sqrt(*this * *this);
}
}; double dist(const Point &a, const Point &b) {
return (a - b).length();
} double cross(const Point &a, const Point &b) {
return a.x * b.y - a.y * b.x;
} double cross(const Point &o, const Point &a, const Point &b) {
return cross(a - o, b - o);
} double Point_to_Line(const Point &p, const Point &st, const Point &ed) {
return fabs(cross(p, st, ed)) / dist(st, ed);
} Point intersection(const Point &u1, const Point &u2, const Point &v1, const Point &v2) {
double t = cross(u1 - v1, v1 - v2) / cross(u1 - u2, v1 - v2);
return u1 + (u2 - u1) * t;
} struct Circle {
Point c;
double r;
Circle() {}
Circle(Point c, double r): c(c), r(r) {}
void read() {
c.read();
scanf("%lf", &r);
}
bool contain(const Circle &rhs) const {
return sgn(dist(c, rhs.c) + rhs.r - r) <= ;
}
bool contain(const Point &p) const {
return sgn(dist(c, p) - r) <= ;
}
bool intersect(const Circle &rhs) const {
return sgn(dist(c, rhs.c) - r - rhs.r) < ;
}
bool tangency(const Circle &rhs) const {
return sgn(dist(c, rhs.c) - r - rhs.r) == ;
}
}; int intersection(const Circle &cir, const Point &st, const Point &ed, Point &p1, Point &p2) {
if(sgn(Point_to_Line(cir.c, st, ed) - cir.r) > ) return ;
Point p = cir.c + (ed - st).rotate();
p = intersection(p, cir.c, st, ed);
double t = sqrt(sqr(cir.r) - sqr(dist(p, cir.c))) / dist(st, ed);
p1 = p + (ed - st) * t;
p2 = p - (ed - st) * t;
return - (p1 == p2);
} int intersection(const Circle &c1, const Circle &c2, Point &p1, Point &p2) {
if(c1.contain(c2) || c2.contain(c1)) return ;
if(!c1.intersect(c2) && !c1.tangency(c2)) return ;
double t = 0.5 * ( + (sqr(c1.r) - sqr(c2.r)) / sqr(dist(c1.c, c2.c)));
Point u = c1.c + (c2.c - c1.c) * t, v = u + (c1.c - c2.c).rotate();
return intersection(c1, u, v, p1, p2);
} struct Graph {
int head[MAXV], ecnt;
int to[MAXE], next[MAXE];
double cost[MAXE];
int n, st, ed; void init() {
memset(head, -, sizeof(head));
ecnt = ;
} void add_edge(int u, int v, double c) {
to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
} double dis[MAXV];
bool vis[MAXV]; double dijksrta(int st, int ed, int n) {
for(int i = ; i < n; ++i) dis[i] = INF;
dis[st] = ;
memset(vis, , sizeof(vis));
while(true) {
int u = -; double d = INF;
for(int i = ; i < n; ++i) if(!vis[i])
if(dis[i] < d) d = dis[i], u = i;
if(d == INF) break;
vis[u] = true;
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(!vis[v]) dis[v] = min(dis[v], dis[u] + cost[p]);
}
}
return dis[ed];
}
} G; Circle cir[MAXN];
int T, n; Point list[MAXV]; bool havePath(Point st, Point ed) {
if(ed < st) swap(st, ed);
if(st == ed) return true;
Point p1, p2;
int pcnt = ;
list[pcnt++] = st;
list[pcnt++] = ed;
for(int i = ; i < n; ++i) {
int c = intersection(cir[i], st, ed, p1, p2);
if(c >= ) list[pcnt++] = p1;
if(c >= ) list[pcnt++] = p2;
}
sort(list, list + pcnt);
for(int i = ; i < pcnt; ++i) {
if(list[i] < st || list[i] == st) continue;
bool flag = false;
for(int j = ; j < n && !flag; ++j)
if(cir[j].contain(list[i]) && cir[j].contain(list[i - ])) flag = true;
if(!flag) return false;
if(list[i] == ed) break;
}
return true;
} Point p[MAXV];
int cnt; double solve() {
Point p1, p2;
cnt = ;
p[cnt++] = cir[].c; p[cnt++] = cir[n - ].c;
for(int i = ; i < n; ++i) {
for(int j = i + ; j < n; ++j) {
int c = intersection(cir[i], cir[j], p1, p2);
if(c >= ) p[cnt++] = p1;
if(c >= ) p[cnt++] = p2;
}
}
G.init();
for(int i = ; i < cnt; ++i) {
for(int j = i + ; j < cnt; ++j)
if(havePath(p[i], p[j])) G.add_edge(i, j, dist(p[i], p[j]));
}
return G.dijksrta(, , cnt);
} int main() {
scanf("%d", &T);
for(int kase = ; kase <= T; ++kase) {
scanf("%d", &n);
for(int i = ; i < n; ++i) cir[i].read();
double res = solve();
if(res == INF) printf("Case %d: No such path.\n", kase);
else printf("Case %d: %.4f\n", kase, res);
}
}
下面是用了一部分解析几何的方法,比上面的还要快……
代码(G++ 437MS):
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <numeric>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXV = MAXN * MAXN * ;
const int MAXE = MAXV * MAXV;
const double EPS = 1e-;
const double INF = 1e100; inline double sqr(double x) {
return x * x;
} inline int sgn(double x) {
return (x > EPS) - (x < -EPS);
} struct Point {
double x, y;
Point() {}
Point(double x, double y): x(x), y(y) {}
void read() {
scanf("%lf%lf", &x, &y);
}
bool operator < (const Point &rhs) const {
if(sgn(x - rhs.x) != ) return x < rhs.x;
return sgn(y - rhs.y) < ;
}
bool operator == (const Point &rhs) const {
return sgn(x - rhs.x) == && sgn(y - rhs.y) == ;
}
Point operator + (const Point &rhs) const {
return Point(x + rhs.x, y + rhs.y);
}
Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
double operator * (const Point &rhs) const {
return x * rhs.x + y * rhs.y;
}
Point operator * (double d) const {
return Point(x * d, y * d);
}
Point operator / (double d) const {
return Point(x / d, y / d);
}
Point rotate() const {
return Point(-y, x);
}
double length() const {
return sqrt(*this * *this);
}
}; double dist(const Point &a, const Point &b) {
return (a - b).length();
} double cosIncludeAngle(const Point &a, const Point &b, const Point &o) {
Point p1 = a - o, p2 = b - o;
return (p1 * p2) / (p1.length() * p2.length());
} struct Circle {
Point c;
double r;
Circle() {}
Circle(Point c, double r): c(c), r(r) {}
void read() {
c.read();
scanf("%lf", &r);
}
bool contain(const Circle &rhs) const {
return sgn(dist(c, rhs.c) + rhs.r - r) <= ;
}
bool contain(const Point &p) const {
return sgn(dist(c, p) - r) <= ;
}
bool intersect(const Circle &rhs) const {
return sgn(dist(c, rhs.c) - r - rhs.r) < ;
}
bool tangency(const Circle &rhs) const {
return sgn(dist(c, rhs.c) - r - rhs.r) == ;
}
}; int intersection(const Point &st, const Point &ed, const Circle &cir, Point &p1, Point &p2) {
double angle = cosIncludeAngle(ed, cir.c, st);
if(isnan(angle)) {
Point v = (ed - st) / dist(st, ed);
p1 = cir.c + v * cir.r;
p2 = cir.c - v * cir.r;
return + (cir.r > );
}
double B = dist(cir.c, st);
double a = , b = - * B * angle, c = sqr(B) - sqr(cir.r);
double delta = sqr(b) - * a * c;
if(sgn(delta) < ) return ;
if(sgn(delta) == ) delta = ;
double x1 = (-b - sqrt(delta)) / ( * a), x2 = (-b + sqrt(delta)) / ( * a);
Point v = (ed - st) / dist(ed, st);
p1 = st + v * x1;
p2 = st + v * x2;
return + sgn(delta);
} int intersection(const Circle &c1, const Circle &c2, Point &p1, Point &p2) {
if(c1.contain(c2) || c2.contain(c1)) return ;
if(!c1.intersect(c2) && !c1.tangency(c2)) return ;
double d = dist(c1.c, c2.c);
double d1 = (sqr(c2.r) + sqr(d) - sqr(c1.r)) / / d;
double d2 = sqrt(sqr(c2.r) - sqr(d1));
Point v1 = c2.c + (c1.c - c2.c) / d * d1;
Point v2 = (c1.c - c2.c).rotate() / d;
p1 = v1 + v2 * d2;
p2 = v1 - v2 * d2;
return - (p1 == p2);
} struct Graph {
int head[MAXV], ecnt;
int to[MAXE], next[MAXE];
double cost[MAXE];
int n, st, ed; void init() {
memset(head, -, sizeof(head));
ecnt = ;
} void add_edge(int u, int v, double c) {
to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; cost[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
} double dis[MAXV];
bool vis[MAXV]; double dijksrta(int st, int ed, int n) {
for(int i = ; i < n; ++i) dis[i] = INF;
dis[st] = ;
memset(vis, , sizeof(vis));
while(true) {
int u = -; double d = INF;
for(int i = ; i < n; ++i) if(!vis[i])
if(dis[i] < d) d = dis[i], u = i;
if(d == INF) break;
vis[u] = true;
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(!vis[v]) dis[v] = min(dis[v], dis[u] + cost[p]);
}
}
return dis[ed];
}
} G; Circle cir[MAXN];
int T, n; Point list[MAXV]; bool havePath(Point st, Point ed) {
if(ed < st) swap(st, ed);
if(st == ed) return true;
Point p1, p2;
int pcnt = ;
list[pcnt++] = st;
list[pcnt++] = ed;
for(int i = ; i < n; ++i) {
int c = intersection(st, ed, cir[i], p1, p2);
if(c >= ) list[pcnt++] = p1;
if(c >= ) list[pcnt++] = p2;
}
sort(list, list + pcnt);
for(int i = ; i < pcnt; ++i) {
if(list[i] < st || list[i] == st) continue;
bool flag = false;
//Point x = (list[i] + list[i - 1]) / 2;
for(int j = ; j < n && !flag; ++j)
if(cir[j].contain(list[i]) && cir[j].contain(list[i - ])) flag = true;
if(!flag) return false;
if(list[i] == ed) break;
}
return true;
} Point p[MAXV];
int cnt; double solve() {
Point p1, p2;
cnt = ;
p[cnt++] = cir[].c; p[cnt++] = cir[n - ].c;
for(int i = ; i < n; ++i) {
for(int j = i + ; j < n; ++j) {
int c = intersection(cir[i], cir[j], p1, p2);
if(c >= ) p[cnt++] = p1;
if(c >= ) p[cnt++] = p2;
}
}
G.init();
for(int i = ; i < cnt; ++i) {
for(int j = i + ; j < cnt; ++j)
if(havePath(p[i], p[j])) G.add_edge(i, j, dist(p[i], p[j]));
}
return G.dijksrta(, , cnt);
} int main() {
scanf("%d", &T);
for(int kase = ; kase <= T; ++kase) {
scanf("%d", &n);
for(int i = ; i < n; ++i) cir[i].read();
double res = solve();
if(res == INF) printf("Case %d: No such path.\n", kase);
else printf("Case %d: %.4f\n", kase, res);
}
}