这道ICPC题目描述了一个极具现实意义的场景:外星飞碟在现代城市中的导航问题。与早期地球环境不同,现代都市中高耸的摩天大楼成为了飞碟飞行的主要障碍。题目要求我们为飞碟规划两点之间的最短路径,同时确保飞碟不会与任何摩天大楼相交(可以接触)。
核心挑战在于:
由于飞碟有半径r,我们需要对每个摩天大楼进行"膨胀"处理。具体来说:
这样处理后,飞碟的圆心可以被视为一个点,只要这个点不进入膨胀后的障碍区域,就保证了飞碟本身不与原始障碍物相交。
最短路径将由以下元素交替组成:
关键观察是:最优路径必定是由这些基本元素组成的,任何更复杂的曲线都可以被这些元素的组合所近似。
采用Dijkstra算法来寻找最短路径,将问题建模为图搜索问题:
节点表示:路径上的关键点,包括:
边表示:路径段,包括:
权重:路径段的长度
代码中实现了多种几何判断函数:
cpp复制// 计算两点距离
double dis(double x1, double y1, double x2, double y2) {
double dx = x1-x2, dy = y1-y2;
return sqrt(dx*dx+dy*dy);
}
// 向量点积
double dot(double x1, double y1, double x2, double y2) {
return x1*x2 + y1*y2;
}
// 向量叉积
double cross(double x1, double y1, double x2, double y2) {
return x1*y2 - x2*y1;
}
这是算法中最复杂的部分,需要判断:
例如,线段与矩形的相交检测:
cpp复制bool seg_intersects_rect(double xs, double ys, double xt, double yt,
int xa, int ya, int xb, int yb) {
return point_in_rect(xs, ys, xa, ya, xb, yb) ||
point_in_rect(xt, yt, xa, ya, xb, yb) ||
seg_intersects_seg(xs, ys, xt, yt, xa, ya, xb, yb) ||
seg_intersects_seg(xs, ys, xt, yt, xa, yb, xb, ya);
}
计算点到圆的切线是算法的核心之一。对于点P(xs,ys)和圆心C(xc,yc),半径为r:
代码实现:
cpp复制void solve_src_tangent_rc(double xs, double ys, int s, int c) {
// 确定圆心和方向向量
int xc, yc, dx, dy;
if (c == 0) xc = x_[s], yc = y_[s], dx = -1, dy = -1;
// ...其他情况类似
double vx = xs - xc, vy = ys - yc, m = sqrt(vx*vx + vy*vy);
if (m < r-eps) return; // 点在圆内
double k1 = r*r/m/m, k2 = r*sqrt(m*m - r*r)/m/m;
// 计算两个切点
double x = k1*vx - k2*vy, y = k1*vy + k2*vx;
if (valid(x, y, dx, dy) && direct_fly(xs, ys, x+xc, y+yc))
update({x+xc, y+yc, s, c}, dis(xs, ys, x+xc, y+yc));
x = k1*vx + k2*vy; y = k1*vy - k2*vx;
if (valid(x, y, dx, dy) && direct_fly(xs, ys, x+xc, y+yc))
update({x+xc, y+yc, s, c}, dis(xs, ys, x+xc, y+yc));
}
几何计算中需要注意浮点精度问题:
cpp复制#define eps 1e-9
int sign(double v) {
return abs(v) < eps ? 0 : (v < 0 ? -1 : 1);
}
使用结构体表示路径点:
cpp复制struct arc_p {
double x, y; // 点坐标
int s, c; // 所属障碍物编号和圆弧类型(0-3表示四个角)
bool operator== (const arc_p &rhs) const {
return s == rhs.s && c == rhs.c &&
abs(x-rhs.x) < eps && abs(y-rhs.y) < eps;
}
};
题目提供了多个测试用例,涵盖了各种边界情况:
例如测试用例1:
code复制1 3
2 7 7 1
3 2 6 4
7 5 9 8
1 8 5 9
对应图示中的情况,正确答案是绕行左下角的路径,长度10.570796。
在实现这类几何路径规划算法时,有以下重要经验:
精度处理:
几何特殊情况:
性能考量:
调试技巧:
这个问题的解决展示了计算几何与图搜索算法的完美结合,其中几何建模和碰撞检测的准确性直接决定了算法的正确性,而Dijkstra的应用则保证了能找到全局最优解。