P1027 [NOIP 2001 提高组] Car 的旅行路线

题目描述

又到暑假了,住在城市 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[][]:飞机距离矩阵(跨城市)
  • 初始化时,同一城市的机场在trfl中都存入铁路距离

5. 最短路计算fy函数)

  • 使用Floyd算法 分别对trfl求最短路
  • 这样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;
}
相关推荐
梦游钓鱼1 天前
Logger.h和Logger.cc文件分析
开发语言·c++
mit6.8241 天前
Agent memory发展路线
算法
青桔柠薯片1 天前
Linux I/O多路复用:深入浅出poll与epoll
linux·运维·服务器·算法
REDcker1 天前
Linux C++ 内存泄漏排查分析手册
java·linux·c++
临溟夜空的繁星1 天前
C++ STL-- vector
开发语言·c++
哈哈很哈哈1 天前
逻辑回归Logistic Regression
算法·机器学习·逻辑回归
甄心爱学习1 天前
【极大似然估计/最大化后验】为什么逻辑回归要使用交叉熵损失函数
算法·机器学习·逻辑回归
郝学胜-神的一滴1 天前
深度学习入门全解析:从核心概念到实战基础 | 技术研讨会精华总结
人工智能·python·深度学习·算法·cnn
一方热衷.1 天前
YOLO26-OBB ONNXruntime部署 python/C++
开发语言·c++·python
梯度下降中1 天前
CNN原理精讲
人工智能·算法·机器学习