【最短路 Floyd】最優路線
阿新 • • 發佈:2020-12-04
題意
給定一張\(n\)個點\(m\)條邊的無向圖,無重邊無自環,每個點有點權,每條邊有邊權。
我們定義一條路徑的權值,為這條路徑經過的點權最大值乘以邊權最大值。
對於每個點對\((u,v)\),你都要求出\(u,v\)之間的權值最小的路徑的權值。
資料範圍:\(1 \leq n \leq 500,0 \leq m \leq \frac{n\times (n-1)}2\),邊權和點權不超過\(10^9\)。
思路
看到資料範圍很容易聯想到\(floyd\)。
如果限定點權從小到大,只有不超過這個點權的點能經過,用限定的這個點權大小更新答案。時間複雜度是\(O(n^4)\)的。
考慮\(floyd\)的本質:\(k,i,j\)
對於本題,可以讓\(k\)按點權從小到大列舉點,即限定了點權從小到大,這樣做就是\(floyd\)的複雜度了。
程式碼
#include <cstdio> #include <cstring> #include <algorithm> #define int long long struct node { int v, id; }a[501]; int n, m; int val[501], f[501][501], ans[501][501]; bool cmp(node x, node y) { return x.v < y.v; } signed main() { freopen("path.in", "r", stdin); freopen("path.out", "w", stdout); scanf("%lld %lld", &n, &m); for (int i = 1; i <= n; i++) scanf("%lld", &a[i].v), a[i].id = i, val[i] = a[i].v; memset(f, 127 / 3, sizeof(f)); memset(ans, 127 / 3, sizeof(ans)); for (int i = 1, x, y, w; i <= m; i++) { scanf("%lld %lld %lld", &x, &y, &w); f[x][y] = f[y][x] = w; ans[x][y] = ans[y][x] = w * std::max(val[x], val[y]); } std::sort(a + 1, a + n + 1, cmp); for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (i != j) if (f[i][j] > std::max(f[i][a[k].id], f[a[k].id][j])) f[i][j] = std::max(f[i][a[k].id], f[a[k].id][j]), ans[i][j] = std::min(ans[i][j], f[i][j] * std::max(val[a[k].id], std::max(val[i], val[j]))); for (int i = 1; i <= n; i++, printf("\n")) for (int j = 1; j <= n; j++) if (i == j) printf("0 "); else if (ans[i][j] == 707406378) printf("-1 "); else printf("%lld ", ans[i][j]); }