最优路线 \operatorname{最优路线} 最优路线
题目链接: luogu T145192 \operatorname{luogu\ T145192} luogu T145192 / SSL比赛 1514 \operatorname{SSL比赛\ 1514} SSL比赛 1514
题目
一个 n n n 个点 m m m 条边的无重边无自环的无向图,点有点权,边有边权,定义一条路径的权值为路径经过的点权的最大值乘边权最大值。求任意两点间的权值最小的路径的权值。
输入
第一行两个整数 n , m n,m n,m ,分别表示无向图的点数和边数。
第二行 n n n 个正整数,第 i i i 个正整数表示点 i i i 的点权。
接下来 m m m 行每行三个正整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi ,分别描述一条边的两个端点和边权。
输出
n n n 行每行 n n n 个整数,第 i i i 行第 j j j 个整数表示从 i i i 到 j j j 的路径的最小权值,如果从 i i i 不能到达 j j j ,则该值为 − 1 -1 −1 。特别地,当 i = j i=j i=j 时输出 0 0 0 。
样例输入
3 3
2 3 3
1 2 2
2 3 3
1 3 1
样例输出
0 6 3
6 0 6
3 6 0
数据范围
对于 20 % 20\% 20% 的数据, n ≤ 5 , m ≤ 8 n\le 5,m\le 8 n≤5,m≤8 。
对于 50 % 50\% 50% 的数据, n ≤ 50 n\le 50 n≤50 。
对于 100 % 100\% 100% 的数据, n ≤ 500 , m ≤ n ( n − 1 ) / 2 n\le 500,m\le n(n-1)/2 n≤500,m≤n(n−1)/2 ,边权和点权不超过 1 0 9 10^9 109 。
思路
这道题是一道 Floyed 最短路。
我们可以看出边权我们可以直接 Floyed 搞,但是点权呢?
我们可以发现,如果我们把点按点权从小到大排,按这个顺序作为中转站,我们就会发现,新的路径的最大点权一定是这个点或者之前两边的求出来的点。那就通过这个来做 Floyed ,就可以得出答案了。
不过 n 3 n^3 n3 过 500 500 500 需要压一下时间。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rr register
#define ll long long
using namespace std;
struct node {
ll x, num;
}a[501];
ll n, m, b[501], x, y, z, f[501][501], dis[501][501];
bool cmp(node x, node y) {
return x.x < y.x;
}
ll read() {
//快读
ll an = 0, zhengfu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') zhengfu = -zhengfu;
c = getchar();
}
while (c >= '0' && c <= '9') {
an = an * 10 + c - '0';
c = getchar();
}
return an * zhengfu;
}
int main() {
memset(f, 0x7f, sizeof(f));//初始化
memset(dis, 0x7f, sizeof(dis));
n = read();//读入
m = read();
for (rr ll i = 1; i <= n; i++) {
f[i][i] = 0;//初始化
b[i] = a[i].x = read();//读入
a[i].num = i;//初始化
}
sort(a + 1, a + n + 1, cmp);//按边权排序
for (rr ll i = 1; i <= m; i++) {
x = read();//读入
y = read();
z = read();
dis[x][y] = dis[y][x] = z;//求出直接距离和权值
f[x][y] = f[y][x] = min(f[x][y], dis[x][y] * max(b[x], b[y]));
}
for (rr ll k = 1; k <= n; k++)//floyed算法
for (rr ll i = 1; i <= n; i++)
for (rr ll j = 1; j <= n; j++)
if (dis[i][j] > max(dis[i][a[k].num], dis[a[k].num][j])) {
dis[i][j] = max(dis[i][a[k].num], dis[a[k].num][j]);
f[i][j] = min(f[i][j], dis[i][j] * (ll)max(b[i], max(b[j], b[a[k].num])));
}
for (rr ll i = 1; i <= n; i++) {
for (rr ll j = 1; j <= n; j++)
if (i == j) printf("0 ");//输出
else if (f[i][j] == 0) printf("-1 ");
else printf("%lld ", f[i][j]);
printf("\n");
}
return 0;
}