luogu 题解:P1027 [NOIP 2001 提高组] Car 的旅行路线
剩下的很显然,计算同一个矩形中两点间的“高速公路”的边权并记录,计算不同矩形的两点间的“航线”的边权并记录,跑 floyd 即可,最后枚举起点与终点的状态。但是由于题目只给出了矩形的三个顶点的坐标,第四个顶点应该自己计算。声明:为了提高代码可读性,此代码采用了 AI 重构。个点,考虑用邻接表、floyd 算法解决此题。一种很显然的做法,注意到数据规模。种不同的状态(矩形的四个顶点)。考虑拆点,拆点
一种很显然的做法,注意到数据规模 S ≤ 100 S \le 100 S≤100,在一座城市中最多有 4 4 4 种不同的状态(矩形的四个顶点)。
考虑拆点,拆点后最多只有 400 400 400 个点,考虑用邻接表、floyd 算法解决此题。
但是由于题目只给出了矩形的三个顶点的坐标,第四个顶点应该自己计算。
假设第一个点是 A ( x 1 , y 1 ) A(x_1, y_1) A(x1,y1),第二个点是 B ( x 2 , y 2 ) B(x_2, y_2) B(x2,y2),第三个点是 C ( x 3 , y 3 ) C(x_3, y_3) C(x3,y3),第三个点是 D ( x 4 , y 4 ) D(x_4, y_4) D(x4,y4)。
有如下三种情况:
-
A B 2 + A C 2 = B C 2 AB^2 + AC^2 = BC^2 AB2+AC2=BC2,此时 x 4 = x 2 + x 3 − x 1 x_4 = x_2 + x_3 - x_1 x4=x2+x3−x1, y 4 = y 2 + y 3 − y 1 y_4 = y_2 + y_3 - y_1 y4=y2+y3−y1, D ( − x 1 + x 2 + x 3 , − y 1 + y 2 + y 3 ) D(-x_1 + x_2 + x_3, -y_1 + y_2 + y_3) D(−x1+x2+x3,−y1+y2+y3)。
不难证明,因为 A B AB AB, A C AC AC 是直角边,因此 A B = C D \mathbf{AB} = \mathbf{CD} AB=CD,由于 A B = ( x 2 − x 1 , y 2 − y 1 ) \mathbf{AB} = (x_2 - x_1, y_2 - y_1) AB=(x2−x1,y2−y1), C ( x 3 , x 4 ) C(x_3, x_4) C(x3,x4),所以 D = C + A B D = C + \mathbf{AB} D=C+AB。
-
同理, A B 2 + B C 2 = A C 2 AB^2 + BC^2 = AC^2 AB2+BC2=AC2 时, D ( x 1 − x 2 + x 3 , y 1 − y 2 + y 3 ) D(x_1 - x_2 + x_3, y_1 - y_2 + y_3) D(x1−x2+x3,y1−y2+y3)
-
A C 2 + B C 2 = A B 2 AC^2 + BC^2 = AB^2 AC2+BC2=AB2 时, D ( x 1 + x 2 − x 3 , y 1 + y 2 − y 3 ) D(x_1 + x_2 - x_3, y_1 + y_2 - y_3) D(x1+x2−x3,y1+y2−y3)
剩下的很显然,计算同一个矩形中两点间的“高速公路”的边权并记录,计算不同矩形的两点间的“航线”的边权并记录,跑 floyd 即可,最后枚举起点与终点的状态。时间复杂度:拆点 O ( T ∗ S ) O(T*S) O(T∗S),建边 O ( T ∗ S 2 ) O(T*S^2) O(T∗S2),floyd O ( T ∗ S 3 ) O(T*S^3) O(T∗S3),总复杂度 O ( T ∗ S 3 ) O(T*S^3) O(T∗S3)。
代码
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
// 快速读入整数的函数
inline int read() {
int f = 1, x = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
typedef long long ll;
const ll INF = 0x7f7f7f7f; // 用于表示无穷大
const int N = 410; // 最大点数
// 变量定义
ll s, A, B, T; // s: 矩形数量, A 和 B: 起点和终点矩形编号, T: 测试用例数量
double ans, t, dis[N][N]; // ans: 最终答案, t: 普通路径的权重, dis: 距离矩阵
double x[N], y[N], w[110]; // x, y: 点的坐标, w: 矩形的权重
// 计算两点之间的欧几里得距离
double getDistance(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
// 计算两点之间的平方距离(避免开方,提高效率)
double squaredDistance(double x1, double y1, double x2, double y2) {
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}
int main() {
T = read(); // 读取测试用例数量
while (T--) {
memset(dis, 0, sizeof(dis)); // 初始化距离矩阵为0
ans = INF; // 初始化答案为无穷大
// 读取输入数据
s = read(); // 矩形数量
t = read(); // 普通路径的权重
A = read(); // 起点矩形编号
B = read(); // 终点矩形编号
// 输入每个矩形的四个点和权重
for (int i = 1; i <= s; i++) {
// 读取矩形的三个点的坐标
x[(i - 1) * 4 + 1] = read();
y[(i - 1) * 4 + 1] = read();
x[(i - 1) * 4 + 2] = read();
y[(i - 1) * 4 + 2] = read();
x[(i - 1) * 4 + 3] = read();
y[(i - 1) * 4 + 3] = read();
w[i] = read(); // 读取矩形的权重
// 计算三个边的平方距离
double disAB = squaredDistance(x[(i - 1) * 4 + 1], y[(i - 1) * 4 + 1],
x[(i - 1) * 4 + 2], y[(i - 1) * 4 + 2]);
double disAC = squaredDistance(x[(i - 1) * 4 + 1], y[(i - 1) * 4 + 1],
x[(i - 1) * 4 + 3], y[(i - 1) * 4 + 3]);
double disBC = squaredDistance(x[(i - 1) * 4 + 2], y[(i - 1) * 4 + 2],
x[(i - 1) * 4 + 3], y[(i - 1) * 4 + 3]);
// 根据三个边的关系计算第四个点的坐标
if (disAB + disAC == disBC) {
x[i * 4] = x[(i - 1) * 4 + 2] + x[(i - 1) * 4 + 3] - x[(i - 1) * 4 + 1];
y[i * 4] = y[(i - 1) * 4 + 2] + y[(i - 1) * 4 + 3] - y[(i - 1) * 4 + 1];
} else if (disAB + disBC == disAC) {
x[i * 4] = x[(i - 1) * 4 + 1] + x[(i - 1) * 4 + 3] - x[(i - 1) * 4 + 2];
y[i * 4] = y[(i - 1) * 4 + 1] + y[(i - 1) * 4 + 3] - y[(i - 1) * 4 + 2];
} else if (disBC + disAC == disAB) {
x[i * 4] = x[(i - 1) * 4 + 2] + x[(i - 1) * 4 + 1] - x[(i - 1) * 4 + 3];
y[i * 4] = y[(i - 1) * 4 + 2] + y[(i - 1) * 4 + 1] - y[(i - 1) * 4 + 3];
}
}
// 初始化距离矩阵
for (int i = 1; i <= s * 4; i++) {
for (int j = 1; j <= s * 4; j++) {
if (i != j) {
if ((i - 1) / 4 != (j - 1) / 4) {
// 如果点i和点j不属于同一个矩形,使用普通路径权重t
dis[i][j] = t * getDistance(x[i], y[i], x[j], y[j]);
} else {
// 如果点i和点j属于同一个矩形,使用该矩形的权重w
dis[i][j] = w[(i - 1) / 4 + 1] * getDistance(x[i], y[i], x[j], y[j]);
}
}
}
}
// 使用Floyd-Warshall算法计算所有点对之间的最短路径
for (int k = 1; k <= s * 4; k++) {
for (int i = 1; i <= s * 4; i++) {
for (int j = 1; j <= s * 4; j++) {
// 更新最短路径
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
// 计算从起点矩形A到终点矩形B的最短路径
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
// 遍历起点矩形A和终点矩形B的所有四个点,找到最短路径
ans = min(ans, dis[(A - 1) * 4 + i][(B - 1) * 4 + j]);
}
}
// 输出结果,保留一位小数
printf("%.1lf\n", ans);
}
return 0;
}
声明:为了提高代码可读性,此代码采用了 AI 重构。
更多推荐
所有评论(0)