题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4063
Description
Input
Output
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 }