Problem - 4063

  几何加简单最短路。

  题意是给出若干圆的圆心以及半径,求出从给出的起点到终点的最短路径的长度,可以移动的区域是圆覆盖到的任意一个位置。

  做法是这样的,对圆两两求交点,用这些得到的交点以及起点和终点作为我们要构造的图的顶点。因为我们要的是最短路径,所以如果我们要从一个区域穿越到另一区域的时候,必然是经过这些交点的。然后我们可以对这些交点两两判断是否能够相互到达。这个判断才是这道题的关键。判断的方法可以有几种,我想到的一是先求出直线与所有圆的交点,排序以后判断所有的圆能否覆盖掉这条线段;而我的是另一种方法,就是用一个队列,将还没有被覆盖的线段存在队列里,每次跟圆相交判断线段是否仍未被覆盖。

  最后来一个单源最短路就搞掂了!

代码如下:

 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue> using namespace std; const double EPS = 1e-;
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) {}
bool operator < (Point a) const { return sgn(x - a.x) < || sgn(x - a.x) == && y < a.y;}
bool operator <= (Point a) const { return (sgn(x - a.x) < || sgn(x - a.x) == && sgn(y - a.y) < ) || (sgn(x - a.x) == && sgn(y - a.y) == );}
bool operator == (Point a) const { return sgn(x - a.x) == && sgn(y - a.y) == ;}
void print() { cout << x << '~' << y << endl;}
} ;
template <class T> T sqr(T x) { return x * x;}
typedef Point Vec;
Vec operator + (Vec a, Vec b) { return Vec(a.x + b.x, a.y + b.y);}
Vec operator - (Vec a, Vec b) { return Vec(a.x - b.x, a.y - b.y);}
Vec operator * (Vec a, double p) { return Vec(a.x * p, a.y * p);}
Vec operator / (Vec a, double p) { return Vec(a.x / p, a.y / p);} inline double dotDet(Vec a, Vec b) { return a.x * b.x + a.y * b.y;}
inline double dotDet(Point o, Point a, Point b) { return dotDet(a - o, b - o);}
inline double crossDet(Vec a, Vec b) { return a.x * b.y - a.y * b.x;}
inline double crossDet(Point o, Point a, Point b) { return crossDet(a - o, b - o);}
inline double vecLen(Vec x) { return sqrt(dotDet(x, x));}
inline double angle(Vec v) { return atan2(v.y, v.x);}
inline double angle(Vec a, Vec b) { return acos(dotDet(a, b) / vecLen(a) / vecLen(b));}
inline Vec vecUnit(Vec x) { return x / vecLen(x);}
inline Vec rotate(Vec x, double rad) { return Vec(x.x * cos(rad) - x.y * sin(rad), x.x * sin(rad) + x.y * cos(rad));}
inline Vec normal(Vec x) { return Vec(-x.y, x.x) / vecLen(x);} struct Line {
Point s, t;
Line() {}
Line(Point s, Point t) : s(s), t(t) {}
Vec vec() { return t - s;}
Point point(double x) { return s + vec() * x;}
} ;
typedef Line Seg; inline bool onSeg(Point x, Point a, Point b) { return sgn(crossDet(a - x, b - x)) == && sgn(dotDet(a - x, b - x)) < ;}
inline bool onSeg(Point x, Seg s) { return onSeg(x, s.s, s.t);} inline Point lineIntersect(Point P, Vec v, Point Q, Vec w) { return P + v * (crossDet(w, P - Q) / crossDet(v, w));}
inline Point lineIntersect(Line a, Line b) { return lineIntersect(a.s, a.vec(), b.s, b.vec());} struct Circle {
Point c;
double r;
Circle() {}
Circle(Point c, double r) : c(c), r(r) {}
Point point(double a) { return Point(c.x + cos(a) * r, c.y + sin(a) * r);}
} ;
int lineCircleIntersect(Line L, Circle C, vector<Point> &sol) {
Vec nor = normal(L.vec());
Point mid = lineIntersect(C.c, nor, L.s, L.vec());
double len = sqr(C.r) - sqr(vecLen(C.c - mid));
if (sgn(len) < ) return ;
if (sgn(len) == ) { sol.push_back(mid); return ;}
Vec dis = vecUnit(L.vec());
len = sqrt(len);
sol.push_back(mid + dis * len);
sol.push_back(mid - dis * len);
return ;
} int circleCircleIntersect(Circle C1, Circle C2, vector<Point> &sol) {
double d = vecLen(C1.c - C2.c);
if (sgn(d) == ) {
if (sgn(C1.r - C2.r) == ) return -;
return - + (C1.r > C2.r);
}
if (sgn(C1.r + C2.r - d) < ) return ;
if (sgn(fabs(C1.r - C2.r) - d) > ) return - + (C1.r > C2.r);
double a = angle(C2.c - C1.c);
double da = acos((sqr(C1.r) + sqr(d) - sqr(C2.r)) / (2.0 * C1.r * d));
Point p1 = C1.point(a - da), p2 = C1.point(a + da);
sol.push_back(p1);
// p1.print();
if (p1 == p2) return ;
sol.push_back(p2);
// p2.print();
return ;
} inline bool ptInCircle(Point p, Circle c) { return sgn(vecLen(c.c - p) - c.r) <= ;} const int N = ;
Circle dev[N];
vector<Point> vex;
int sid, tid;
double mat[N * N][N * N]; Seg qseg[N * N]; double cal(int pi, int pj, int n) {
// queue<Seg> seg;
vector<Point> ip;
int qh, qt;
qh = qt = ;
// while (!seg.empty()) seg.pop();
if (vex[pj] < vex[pi]) swap(pi, pj);
Seg L = Seg(vex[pi], vex[pj]);
// seg.push(L);
qseg[qt++] = L;
for (int i = ; i < n; i++) {
// int sz = seg.size();
int sz = qt - qh;
for (int j = ; j < sz; j++) {
// Seg tmp = seg.front();
// seg.pop();
Seg tmp = qseg[qh++];
// if (pi == 0 && pj == 2) {
// tmp.s.print();
// tmp.t.print();
// puts("tmp");
// }
ip.clear();
if (lineCircleIntersect(L, dev[i], ip) == ) {
if (ip[] < ip[]) swap(ip[], ip[]);
// if (pi == 0 && pj == 4) {
// ip[0].print();
// ip[1].print();
// puts("ip");
// }
if (ip[] <= tmp.s || tmp.t <= ip[])
// seg.push(tmp);
qseg[qt++] = tmp;
else if (tmp.s <= ip[] && ip[] <= tmp.t) {
if (vecLen(tmp.s - ip[]) > EPS)
// seg.push(Seg(tmp.s, ip[0]));
qseg[qt++] = Seg(tmp.s, ip[]);
if (vecLen(tmp.t - ip[]) > EPS)
// seg.push(Seg(ip[1], tmp.t));
qseg[qt++] = Seg(ip[], tmp.t);
} else if (tmp.s < ip[] && ip[] <= tmp.t && sgn(vecLen(tmp.s - ip[])))
// seg.push(Seg(tmp.s, ip[0]));
qseg[qt++] = Seg(tmp.s, ip[]);
else if (tmp.s <= ip[] && ip[] < tmp.t && sgn(vecLen(ip[] - tmp.t)))
// seg.push(Seg(ip[1], tmp.t));
qseg[qt++] = Seg(ip[], tmp.t);
} else
// seg.push(tmp);
qseg[qt++] = tmp;
}
// if (seg.size() == 0)
if (qh == qt)
return vecLen(vex[pi] - vex[pj]);
}
return -1.0;
} void PRE(int n) {
vex.clear();
for (int i = ; i < n; i++) {
cin >> dev[i].c.x >> dev[i].c.y >> dev[i].r;
// vex.push_back(dev[i].c);
}
vex.push_back(dev[].c);
vex.push_back(dev[n - ].c);
Point ps = dev[].c, pt = dev[n - ].c;
for (int i = ; i < n; i++) {
for (int j = ; j < i; j++) {
// cout << i << " = = " << j << endl;
circleCircleIntersect(dev[i], dev[j], vex);
}
}
sort(vex.begin(), vex.end());
int t = (int) (unique(vex.begin(), vex.end()) - vex.begin());
while (vex.size() > t) vex.pop_back();
// cout << "size " << vex.size() << endl;
for (int i = , sz = vex.size(); i < sz; i++) {
if (vex[i] == ps) sid = i;
if (vex[i] == pt) tid = i;
for (int j = ; j <= i; j++) {
if (i == j) mat[i][j] = 0.0;
else mat[i][j] = mat[j][i] = cal(i, j, n);
}
}
// cout << sid << ' ' << tid << endl;
// for (int i = 0, sz = vex.size(); i < sz; i++) {
// vex[i].print();
// for (int j = 0; j < sz; j++) printf("%7.4f ", mat[i][j]);
// cout << endl;
// }
} const double FINF = 1e100;
double dis[N * N];
int q[N * N << ];
double spfa() {
int sz = vex.size();
// queue<int> Q;
// while (!Q.empty()) Q.pop();
int qh, qt;
qh = qt = ;
for (int i = ; i < sz; i++) dis[i] = FINF;
dis[sid] = 0.0;
// Q.push(sid);
q[qt++] = sid;
// while (!Q.empty()) {
while (qh < qt) {
// int cur = Q.front();
// Q.pop();
int cur = q[qh++];
for (int i = ; i < sz; i++) {
if (mat[cur][i] < ) continue;
if (dis[i] > dis[cur] + mat[cur][i]) {
dis[i] = dis[cur] + mat[cur][i];
// Q.push(i);
q[qt++] = i;
}
}
}
// for (int i = 0; i < sz; i++) cout << dis[i] << ' '; cout << endl;
return dis[tid];
} int main() {
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
int T, n;
cin >> T;
for (int cas = ; cas <= T; cas++) {
cin >> n;
PRE(n);
printf("Case %d: ", cas);
double ans = spfa();
if (ans < FINF) printf("%.4f\n", ans);
else puts("No such path.");
}
return ;
}

附加自己出的数据:

 8
2
0 0 1
2 0 1
2
0 0 1
4 1 2
3
-3 0 2
0 2 2
3 0 2
3
-3 0 2
0 3 3
3 0 2
6
-6 0 2
-3 0 2
0 3 3
3 0 2
7 0 2
0 8 2
10
-6 0 2
-3 0 2
0 3 3
3 0 2
7 0 2
0 8 2
-4 8 2
-8 8 2
-7 2 2
-8 4 2
3
0 10 7
-1 -1 100
10 0 7
3
-3 0 2
0 3 3
3 0 2

——written by Lyon

hdu 4063 Aircraft (Geometry + SP)的更多相关文章

  1. 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 th ...

  2. HDU 4063 Aircraft --几何,最短路

    题意: 给一些圆,要求从第一个圆的圆心走到最后一个圆的圆心,中间路径必须在某个圆内,求最短路径的长度. 解法: 易知要保持在圆内且路径最短,走两圆相交的点能使路径尽量短,所以我们找出所有的两圆相交的点 ...

  3. hdu 4063 Aircraft(计算几何+最短路)

    不说了...说多了都是泪...从昨天下午一直wa到现在,直到刚刚才让人帮我找到所谓的“bug”,其实也算不上bug... 这个题的思路就是:找出平面上的所有点:所有圆的交点以及所有圆的圆心.然后依次判 ...

  4. HDU 5298 Solid Geometry Homework 暴力

    Solid Geometry Homework 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5298 Description Yellowstar ...

  5. hdu 4063 福州赛区网络赛 圆 ****

    画几个图后,知道路径点集一定是起点终点加上圆与圆之间的交点,枚举每两个点之间是否能走,能走则连上线,然后求一遍最短路即可 #include<cstdio> #include<cstd ...

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

    Aircraft Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  7. HDU - 6242:Geometry Problem(随机+几何)

    Alice is interesting in computation geometry problem recently. She found a interesting problem and s ...

  8. hdu 4179 Difficult Routes (SP)

    Problem - 4179 坑了我一个晚上的SP题. 题意是,给出若干空间中的点,给出其中某些点之间是有直线线段路径相连的.要求求出一条从s开始到t结束的路径,它的难度是d.难度的计算是空间线段两点 ...

  9. 【转载】图论 500题——主要为hdu/poj/zoj

    转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...

随机推荐

  1. iTerm2+oh-my-zsh配色

      效果图,很帅气有木有 一.首先安装iTem2 安装好后的截图如下:   安装好后的截图 二.安装oh-my-zsh. sh -c "$(curl -fsSL https://raw.gi ...

  2. Leetcode643.Maximum Average Subarray I子数组的最大平均数1

    给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.75 解释: 最大平均数 (12- ...

  3. 基于 DataLakeAnalytics 的数据湖实践

    随着软硬件各方面条件的成熟,数据湖(Data Lake)已经越来越受到各大企业的青睐, 与传统的数仓实践不一样的是,数据湖不需要专门的“入仓”的过程,数据在哪里,我们就从哪里读取数据进行分析.这样的好 ...

  4. unity如何查找某个脚本挂在了哪些物体上

    在开发中往往会遇到一个问题:不知道整个场景中究竟有哪些物体挂载了某一个脚本.如果挨个查找太麻烦了,下面有一种方法可以快速找到解决这个问题. 在unity的Window里有一项Editor tests ...

  5. querySelector与getElementBy系列的区别

    getElementBy系列 document.getElementsByTagName('tag'); document.getElementById('id'); document.getElem ...

  6. day38 20-Spring与Junit整合

    package cn.itcast.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springfra ...

  7. POJ1190 洛谷P1731 NOI1999 生日蛋糕

    生日蛋糕(蛋糕是谁?) Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20272   Accepted: 7219 Desc ...

  8. 技巧专题3(cdq分治、整体二分等)

    cdq分治与整体二分 cdq来源于2008年国家集训队作业陈丹琦(雅礼巨佬),用一个log的代价完成从静态到动态(很多时候是减少时间那一维的). 对于一个时间段[L, R],我们取mid = (L + ...

  9. 七.Deque的应用案例-回文检查

    - 回文检测:设计程序,检测一个字符串是否为回文. - 回文:回文是一个字符串,读取首尾相同的字符,例如,radar toot madam. - 分析:该问题的解决方案将使用 deque 来存储字符串 ...

  10. KiCad EDA 如何修改 Pcbnew 线路板的背景色?

    KiCad EDA 如何修改 Pcbnew 线路板的背景色? 关于背景色,传统的原理图是白色,线路板是黑色. EDA 软件 类型 颜色 Protel 原理图 浅黄色 Protel PCB 黑色 Orc ...