zoukankan      html  css  js  c++  java
  • [题目][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 算法

  • 相关阅读:
    iOS 整理面试题(上)
    2021年十大白马名单
    RabbitMQ:消息重复消费
    RabbitMQ:保证消息的顺序性
    RabbitMQ:保证消息的可靠性传输
    AWS S3 大文件分片上传
    rebase 用法小结
    Flask at scale
    MySQL分区
    动态规划示例题
  • 原文地址:https://www.cnblogs.com/jinkun113/p/13792527.html
Copyright © 2011-2022 走看看