题解:P1027 [NOIP 2001 提高组] Car 的旅行路线
Retoayd
·
·
题解
这道题硬控我 1 小时。。。
题目难点:
主要是输入只告诉了我们三个点的坐标,所以需要求第四个点的坐标,要是每种情况都讨论一边的话代码比较长(但也能做),所以推荐写循环。剩下的就是最短路了,这里用 Floyd 就行了。
求第四点的方法:
初中数学中我们学到了两点间距离公式,中点公式和勾股定理,运用这三点,就能求出第四点的坐标了。
代码实现:
void work(int xx) {
int ap, bp, cp; //cp代表直角三角形中斜边所对应的点,ap和bp代表另外两点
for(int i = 0; i <= 2; i++) {
for(int j = 0; j <= 2; j++) {
for(int l = 0; l <= 2; l++) {
if(i == j || j == l || i == l) continue;
double ka = dis2(a[xx].x[i], a[xx].y[i], a[xx].x[j], a[xx].y[j]);
double kb = dis2(a[xx].x[j], a[xx].y[j], a[xx].x[l], a[xx].y[l]);
double kc = dis2(a[xx].x[i], a[xx].y[i], a[xx].x[l], a[xx].y[l]);
if(ka + kb == kc) ap = l, bp = i, cp = j; //勾股定理判断是否构成直角三角形
else continue;
}
}
}
double midx = (a[xx].x[ap] + a[xx].x[bp]) / 2.0, midy = (a[xx].y[ap] + a[xx].y[bp]) / 2.0;
midx *= 2, midy *= 2;
newx = midx - a[xx].x[cp], newy = midy - a[xx].y[cp];
return;
}
最重要的一点,这里求两点间距离的 dis2 函数千万不要开根号,不然会有精度损失,导致没有答案。
```
double dis2(double a1, double b1, double a2, double b2) {
return (a1 - a2) * (a1 - a2) * 1.0 + (b1 - b2) * (b1 - b2) * 1.0;
}
```
### 还有一个技巧:
除了 $a$ 数组存每一个城市的机场坐标以及里程费以外,再开一个数组 $b$,保存每个机场的坐标以及从属的城市编号,这使后续操作方便许多。
就是这样:
```
struct Node {
double x[5], y[5], t;
} a[N];
struct Nod {
int x, y, id;
} b[N];
```
这样,在最后求 $A$ 到 $B$ 城市的最少消耗时,就能够这样实现了(个人认为这样方便点):
```
void print() {
double res = 1000000000.0;
for(int i = 1; i <= idx; i++) //idx表示机场个数
for(int j = 1; j <= idx; j++)
if(b[i].id == A && b[j].id == B)
if(res > f[i][j]) res = f[i][j];
printf("%.1lf\n", res);
}
```
最后,别忘了初始化做 Floyd 用的 $f$ 数组。
### 完整代码实现:
```
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e2 + 5;
struct Node { double x[5], y[5], t; } a[N];
struct Nod { int x, y, id; } b[N];
int T, n, A, B, idx;
double t, newx, newy, f[N][N];
double dis2(double a1, double b1, double a2, double b2) { return (a1 - a2) * (a1 - a2) * 1.0 + (b1 - b2) * (b1 - b2) * 1.0; }
double dis(double a1, double b1, double a2, double b2) { return (double)sqrt((a1 - a2) * (a1 - a2) * 1.0 + (b1 - b2) * (b1 - b2) * 1.0); }
void work(int xx) {
int ap, bp, cp;
for(int i = 0; i <= 2; i++) {
for(int j = 0; j <= 2; j++) {
for(int l = 0; l <= 2; l++) {
if(i == j || j == l || i == l) continue;
double ka = dis2(a[xx].x[i], a[xx].y[i], a[xx].x[j], a[xx].y[j]);
double kb = dis2(a[xx].x[j], a[xx].y[j], a[xx].x[l], a[xx].y[l]);
double kc = dis2(a[xx].x[i], a[xx].y[i], a[xx].x[l], a[xx].y[l]);
if(ka + kb == kc) ap = l, bp = i, cp = j;
else continue;
}
}
}
double midx = (a[xx].x[ap] + a[xx].x[bp]) / 2.0, midy = (a[xx].y[ap] + a[xx].y[bp]) / 2.0;
midx *= 2, midy *= 2;
newx = midx - a[xx].x[cp], newy = midy - a[xx].y[cp];
return;
}
void init() {
for(int i = 1; i <= idx; i++) {
for(int j = 1; j <= idx; j++) {
if(b[i].id == b[j].id) f[i][j] = f[j][i] = dis(b[i].x, b[i].y, b[j].x, b[j].y) * a[b[i].id].t;
else f[i][j] = f[j][i] = dis(b[i].x, b[i].y, b[j].x, b[j].y) * t;
}
}
return;
}
void Floyd() {
for(int k = 1; k <= idx; k++)
for(int i = 1; i <= idx; i++)
for(int j = 1; j <= idx; j++)
if(f[i][j] > f[i][k] + f[k][j]) f[i][j] = f[i][k] + f[k][j];
return;
}
void print() {
double res = 1000000000.0;
for(int i = 1; i <= idx; i++)
for(int j = 1; j <= idx; j++)
if(b[i].id == A && b[j].id == B)
if(res > f[i][j]) res = f[i][j];
printf("%.1lf\n", res);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> T;
while(T--) {
cin >> n >> t >> A >> B;
idx = 0;
for(int i = 1; i <= n; i++) {
cin >> a[i].x[0] >> a[i].y[0] >> a[i].x[1] >> a[i].y[1] >> a[i].x[2] >> a[i].y[2] >> a[i].t;
newx = newy = 0;
work(i);
a[i].x[3] = newx, a[i].y[3] = newy;
for(int j = 0; j <= 3; j++) b[++idx].id = i, b[idx].x = a[i].x[j], b[idx].y = a[i].y[j];
}
init(), Floyd(), print();
}
return 0;
}
```