原题链接:https://www.luogu.com.cn/problem/P1027
题目描述
又到暑假了,住在城市 A 的 Car 想和朋友一起去城市旅游。
她知道每个城市都有 4 个飞机场,分别位于一个矩形的 4 个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第 i 个城市中高速铁路了的单位里程价格为 Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 t。
注意:图中并没有标出所有的铁路与航线。
那么 Car 应如何安排到城市 B 的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
找出一条从城市 A 到 B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
输入格式
第一行为一个正整数 n,表示有 n 组测试数据。
每组的第一行有 4 个正整数 S,t,A,B。
S 表示城市的个数,t 表示飞机单位里程的价格,A,B 分别为城市A,B 的序号。
接下来有 S 行,其中第 i 行均有 7 个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的 (xi1,yi1),(xi2,yi2),(xi3,yi3),分别是第 i 个城市中任意 3 个机场的坐标,Ti 为第 i 个城市高速铁路单位里程的价格。
输出格式
共有 n 行,每行 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% 的数据,1≤n≤10,1≤S≤100,1≤A,B≤S。
【题目来源】
NOIP 2001 提高组第四题
解题思路:
首先我们对于每一个城市题目只给了我们三个机场的坐标,那么我们肯定需要求出第四个机场的坐标,下面画个图描述一下:
此时每个城市的四个机场的坐标都已经知道了,那么我们不妨进行编号,对于第一个城市的四个机场编号为1,2,3,4,对第二个城市的四个机场编号为5,6,7,8,后面的城市依此类推,假设某个机场的编号为k,那么我们可以通过(k-1)/4+1求出这个机场属于第几个城市,我们用d[i][j]记录机场i到机场j的最小花费,然后就将问题转换为了求A城市到B城市的最短路,由于S最大是100,也就是最多只有100个城市,那么最多只有400个机场,也就是图中最多只有400个点,那么我们可以直接采用floyd求最短路即可,求完最短路之后,最终答案就是从A中四个机场中的任意一个机场到达B中任意一个机场的最短路,直接遍历求一遍答案即可。
时间复杂度:O(n^3),floyd算法的时间复杂度为O(n^3)。
空间复杂度:O(400^2),因为最多有400个点。
cpp代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int N = 110, M = 410;
int n;
int S, A, B, t;
int x[M], y[M], T[N];
double d[M][M];
double dist(int x1, int y1, int x2, int y2) //求俩点的距离
{
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
double dist_square(int x1, int y1, int x2, int y2) //求俩个点距离的平分
{
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}
void floyd() //floyd算法求最短路
{
for (int k = 1; k <= S * 4; k++)
for (int i = 1; i <= S * 4; i++)
for (int j = 1; j <= S * 4; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
cin >> n;
while (n--)
{
scanf("%d%d%d%d", &S, &t, &A, &B);
for (int i = 1; i <= S; i++)
{
scanf("%d%d%d%d%d%d%d", &x[(i - 1) * 4 + 1], &y[(i - 1) * 4 + 1], &x[(i - 1) * 4 + 2], &y[(i - 1) * 4 + 2], &x[(i - 1) * 4 + 3], &y[(i - 1) * 4 + 3], &T[i]);
int dab = dist_square(x[(i - 1) * 4 + 1], y[(i - 1) * 4 + 1], x[(i - 1) * 4 + 2], y[(i - 1) * 4 + 2]);
int dac = dist_square(x[(i - 1) * 4 + 1], y[(i - 1) * 4 + 1], x[(i - 1) * 4 + 3], y[(i - 1) * 4 + 3]);
int dbc = dist_square(x[(i - 1) * 4 + 2], y[(i - 1) * 4 + 2], x[(i - 1) * 4 + 3], y[(i - 1) * 4 + 3]);
if (dab + dac == dbc) //推公式,然后根据勾股定理求出对角线,然后根据推出的公式求出第四个点的坐标
{
x[i * 4] = x[(i - 1) * 4 + 2] + x[(i - 1) * 4 + 3] - x[(i - 1) * 4 + 1];
y[i * 4] = y[(i - 1) * 4 + 2] + y[(i - 1) * 4 + 3] - y[(i - 1) * 4 + 1];
}
if (dab + dbc == dac)
{
x[i * 4] = x[(i - 1) * 4 + 1] + x[(i - 1) * 4 + 3] - x[(i - 1) * 4 + 2];
y[i * 4] = y[(i - 1) * 4 + 1] + y[(i - 1) * 4 + 3] - y[(i - 1) * 4 + 2];
}
if (dac + dbc == dab)
{
x[i * 4] = x[(i - 1) * 4 + 1] + x[(i - 1) * 4 + 2] - x[(i - 1) * 4 + 3];
y[i * 4] = y[(i - 1) * 4 + 1] + y[(i - 1) * 4 + 2] - y[(i - 1) * 4 + 3];
}
}
memset(d, 0, sizeof d); //预处理任意俩点之间的距离
for (int i = 1; i <= S * 4; i++)
for (int j = 1; j <= S * 4; j++)
{
if (i == j)
continue;
if ((i - 1) / 4 == (j - 1) / 4)
d[i][j] = dist(x[i], y[i], x[j], y[j]) * T[(i - 1) / 4 + 1];
else
d[i][j] = dist(x[i], y[i], x[j], y[j]) * t;
}
floyd(); //floyd求最短路
double ans = 2e9; //要求从A城市到B城市的最短路就是从城市A中四个机场中的任意一个机场的到B城市中四个机场中的任意一个机场的最短路
for (int i = 1; i <= 4; i++)
for (int j = 1; j <= 4; j++)
ans = min(ans, d[(A - 1) * 4 + i][(B - 1) * 4 + j]);
printf("%.1lf\n", ans); //输出答案,保留一位小数
}
return 0;
}