[题目][NOIP2001][蓝桥杯ALGO-25] Car 的旅行路线

一、题目

0、题目链接

http://lx.lanqiao.cn/problem.page?gpid=T87(需要登录且需要 VIP 账户)

1、问题描述

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

那么 Car 应如何安排到城市 B 的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。

找出一条从城市 A 到 B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

2、输入格式

第一行有四个正整数 s,t,A,B。

S 表示城市的个数,t 表示飞机单位里程的价格,A,B 分别为城市 A,B 的序号,(1 <= A,B <= S)。

接下来有 S 行,其中第 i 行均有 7 个正整数 xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的 (xi1,yi1),(xi2,yi2),(xi3,yi3) 分别是第 i 个城市中任意三个机场的坐标,Ti 为第 i 个城市高速铁路单位里程的价格。

3、输出格式

一个正整数,表示最小花费,保留一位小数。

4、样例输入

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

5、样例输出

47.6

6、数据规模

0 < S <= 100

(蓝桥杯 OJ 里这道题的格式和样例一通乱扯,不忍直视)

二、分析与思路

一道花里胡哨的最短路问题。首先每一座城市都有四个机场,机场的坐标为矩形的四个角,而题目只给出其中三个,所以第一个任务是求出第四个。矩形的两边并非绝对平行于坐标轴,所以我们需要判断给出的构成三角形的三个点中,哪一个点是直角对应的点。假设这四个点为 A, B, C, D,未给出点 D,点 A 为直角点,则存在:k(A, B) * k(A, C) = -1,其中 k(x, y) 表示点 x, y 构成的直线的斜率。如果两边平行于坐标轴,则需要特判一下。依次枚举给出的三个点中哪一个点满足上述条件即可。

题目给出 n 座城市,我们可以将所有城市的所有机场全部分开来看,即视作 4 * n 个点。属于同一座城市的点之间的通行乘坐火车,否则乘坐飞机。根据不同的单位里程价格,与距离相乘,即可得点与点之间的边权,然后就可以跑最短路了。

由于可以从起点的任一机场出发,亦可抵达终点的任一机场,所以起点和终点均相当于有 4 个,需要在这 4 * 4 = 16 种情况下取最小值,加上数据量极小,可以直接使用多源的 Floyd 算法。当然单源 Dijkstra 算法也可行,要么需要跑多次,要么需要对同一城市的机场进行合并处理,过程略。

三、代码

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define MAXN 405
 5 #define INF 0x7f7f7f7f 
 6 
 7 int n, s, t;
 8 double P, p[MAXN], tx[5], ty[5], x[MAXN], y[MAXN], pri[MAXN][MAXN], ans = INF;
 9 
10 double calc(int a, int b, int c) {
11     if (tx[a] == tx[b] && ty[b] == ty[c] || tx[c] == tx[b] && ty[a] == ty[b]) return -1;
12     return (tx[a] - tx[b]) / (ty[a] - ty[b]) * (tx[b] - tx[c]) / (ty[b] - ty[c]);
13 }
14 
15 double getp(int a, int b) {
16     return sqrt((x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b])) * (a / 4 == b / 4 ? p[a / 4] : P);
17 }
18 
19 int main() {
20     cin >> n >> P >> s >> t;
21     for (int i = 1; i <= n; i++) {
22         for (int j = 1; j <= 3; j++)
23             cin >> tx[j] >> ty[j];
24         if (calc(1, 2, 3) == -1) {
25             tx[4] = tx[1] + tx[3] - tx[2];
26             ty[4] = ty[1] + ty[3] - ty[2];
27         }
28         else if (calc(2, 1, 3) == -1) {
29             tx[4] = tx[2] + tx[3] - tx[1];
30             ty[4] = ty[2] + ty[3] - ty[1];
31         }
32         else {
33             tx[4] = tx[1] + tx[2] - tx[3];
34             ty[4] = ty[1] + ty[2] - ty[3];
35         }
36         for (int j = 1; j <= 4; j++) {
37             int o = i * 4 + j - 5;
38             x[o] = tx[j], y[o] = ty[j];
39         }
40         cin >> p[i - 1];
41     }
42     memset(pri, INF, sizeof(pri));
43     for (int i = 0; i < n * 4; i++)
44         for (int j = 0; j < n * 4; j++)
45             pri[i][j] = pri[j][i] = getp(i, j);
46     for (int i = 0; i < n * 4; i++)
47         for (int j = 0; j < n * 4; j++) {
48             if (i == j) continue;        
49             for (int k = 0; k < n * 4; k++) {
50                 if (j == k || i == k) continue;
51                 pri[i][j] = pri[j][i] = min(pri[i][j], pri[i][k] + pri[j][k]);
52             }
53         }
54     for (int i = 1; i <= 4; i++)
55         for (int j = 1; j <= 4; j++)
56             ans = min(ans, pri[s * 4 + i - 5][t * 4 + j - 5]);
57     cout << fixed << setprecision(1) << ans;
58     return 0;
59 }

四、相关知识点

8.5  最短路  最短路径 Floyd 算法

原文地址:https://www.cnblogs.com/jinkun113/p/13792527.html