题目描述
又到暑假了,住在城市 A 的 Car 想和朋友一起去城市旅游。
她知道每个城市都有 444 个飞机场,分别位于一个矩形的 444 个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第 iii 个城市中高速铁路的单位里程价格为 TiT_iTi,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 ttt。

注意:图中并没有标出所有的铁路与航线。
那么 Car 应如何安排到城市 B 的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
找出一条从城市 A 到 B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
输入格式
第一行为一个正整数 nnn,表示有 nnn 组测试数据。
每组的第一行有 444 个正整数 S,t,A,BS,t,A,BS,t,A,B。
SSS 表示城市的个数,ttt 表示飞机单位里程的价格,AAA,BBB 分别为城市A,B 的序号。
接下来有 SSS 行,其中第 iii 行均有 777 个正整数xi1,yi1,xi2,yi2,xi3,yi3,Tix_{i1},y_{i1},x_{i2},y_{i2},x_{i3},y_{i3},T_ixi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的 (xi1,yi1),(xi2,yi2),(xi3,yi3)(x_{i1},y_{i1}), (x_{i2},y_{i2}), (x_{i3},y_{i3})(xi1,yi1),(xi2,yi2),(xi3,yi3),分别是第 iii 个城市中任意 333 个机场的坐标,TiT_iTi 为第 iii 个城市高速铁路单位里程的价格。
输出格式
共有 nnn 行,每行 111 个数据对应测试数据。
保留一位小数。
输入输出样例 #1
输入 #1
1
3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3
输出 #1
47.5
说明/提示
【数据范围】
对于 100%100\%100% 的数据,1≤n≤101\le n \le 101≤n≤10,1≤S≤1001\le S \le 1001≤S≤100,1≤A,B≤S1\le A,B \le S1≤A,B≤S,0≤t,xi1,yi1,xi2,yi2,xi3,yi3,Ti≤5000\leq t,x_{i1},y_{i1},x_{i2},y_{i2},x_{i3},y_{i3},T_i\leq 5000≤t,xi1,yi1,xi2,yi2,xi3,yi3,Ti≤500。
【题目解析】
1. 数据结构设计
cpp
struct P {
int x, y; // 坐标
int c; // 所属城市编号
int i; // 机场编号
} p[N];
- 用
p[]数组存储所有机场(共4*s个) - 每个机场记录坐标、所属城市、自身编号
2. 矩形第四点计算 (g4函数)
- 已知矩形三个顶点,通过勾股定理判断直角顶点
- 利用平行四边形对角线互相平分的性质求出第四点
3. 建图过程
同一城市内(铁路连接):
- 每个城市的4个机场两两相连
- 距离 = 欧氏距离 × 铁路单价T
不同城市间(飞机连接):
- 所有不同城市的机场两两相连
- 距离 = 欧氏距离 × 飞机单价t
4. 两个距离矩阵
tr[][]:铁路距离矩阵(同一城市内)fl[][]:飞机距离矩阵(跨城市)- 初始化时,同一城市的机场在
tr和fl中都存入铁路距离
5. 最短路计算 (fy函数)
- 使用Floyd算法 分别对
tr和fl求最短路 - 这样
fl[i][j]就表示从机场i到机场j的最优组合(跨城坐飞机+城内坐铁路)
6. 答案求解
- 枚举城市A的4个机场到城市B的4个机场
- 取
fl矩阵中的最小值 - 因为
fl已经包含了所有可能的换乘方案
算法复杂度
- 机场总数:4*s ≤ 400
- Floyd算法:O((4s)³) ≈ 6.4×10⁷,可接受
关键技巧
- Floyd跑两次 :先分别处理铁路和飞机,但最终只用
fl矩阵 - 巧妙融合 :在
fl矩阵中,既保留了同城铁路,又加入了跨城飞机 - 统一处理 :最终答案直接从
fl矩阵读取,无需额外判断换乘
【贴上代码~】
cpp
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 410;
const double INF = 1e20;
struct P {
int x, y;
int c;
int i;
} p[N];
int n, s, t, A, B;
double tr[N][N];
double fl[N][N];
double T;
double d(P a, P b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void g4(P &p1, P &p2, P &p3, P &p4) {
double d12 = d(p1, p2);
double d13 = d(p1, p3);
double d23 = d(p2, p3);
if (fabs(d12 * d12 + d13 * d13 - d23 * d23) < 1e-6) {
p4.x = p2.x + p3.x - p1.x;
p4.y = p2.y + p3.y - p1.y;
} else if (fabs(d12 * d12 + d23 * d23 - d13 * d13) < 1e-6) {
p4.x = p1.x + p3.x - p2.x;
p4.y = p1.y + p3.y - p2.y;
} else {
p4.x = p1.x + p2.x - p3.x;
p4.y = p1.y + p2.y - p3.y;
}
}
void fy(double d[][N], int n) {
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (d[i][k] < INF && d[k][j] < INF) {
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
}
int main() {
cin >> n;
while (n--) {
cin >> s >> t >> A >> B;
for (int i = 0; i < 4 * s; i++) {
for (int j = 0; j < 4 * s; j++) {
if (i == j) {
tr[i][j] = 0;
fl[i][j] = 0;
} else {
tr[i][j] = INF;
fl[i][j] = INF;
}
}
}
for (int i = 0; i < s; i++) {
int id = i * 4;
for (int j = 0; j < 3; j++) {
cin >> p[id + j].x >> p[id + j].y;
p[id + j].c = i;
p[id + j].i = id + j;
}
cin >> T;
g4(p[id], p[id + 1], p[id + 2], p[id + 3]);
p[id + 3].c = i;
p[id + 3].i = id + 3;
for (int j = 0; j < 4; j++) {
for (int k = j + 1; k < 4; k++) {
double di = d(p[id + j], p[id + k]) * T;
tr[id + j][id + k] = tr[id + k][id + j] = di;
fl[id + j][id + k] = fl[id + k][id + j] = di;
}
}
}
for (int i = 0; i < 4 * s; i++) {
for (int j = i + 1; j < 4 * s; j++) {
if (p[i].c != p[j].c) {
double di = d(p[i], p[j]) * t;
fl[i][j] = fl[j][i] = min(fl[i][j], di);
}
}
}
fy(tr, 4 * s);
fy(fl, 4 * s);
double ans = INF;
int st = (A - 1) * 4;
int ed = (B - 1) * 4;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ans = min(ans, fl[st + i][ed + j]);
}
}
printf("%.1f\n", ans);
}
return 0;
}