[题目][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 算法