UVA1416 Warfare And Logistics
- Floyd 分治板子。
首先考虑 Floyd 的本质,是通过一条边去松弛两点的距离。
那么我们做分治。
分治的递归数组,为 \(solve(id,l,r)\) 表示,第 \(id\) 层中,没有 \(l \sim r\) 这段区间的边得到的全局最短路。记录的 \(f(id,i,j)\) 表示第 \(id\) 层中的节点 \(i\) 到 \(j\) 的最短路径。
我们分治往下,加入 \(l\sim mid\) 区间的边,再向 \(mid+1 \sim r\) 的区间中向下分治。下传到底后回溯后向另一边继续分治。
\(id\) 层数每次二分往下,一共 \(\log n\) 层。每次需要回溯,所以记录 \(id\) 和 \(f\) 数组对应。\(f\) 的空间复杂度也就是 \(n^2\log n\)。
向下传递到只有一个 \(solve\) 的区间只有一个始我们就可以记录答案了。
更改 \(f\) 数组时,要把需要的边加进去,这和普通的 Floyd 是一样的。
时间复杂度是 \(O(n^3\log n)\)。
#include<bits/stdc++.h>
#define ll long long
#define int ll
#define debug(x) cout<<#x<<"[:]"<<x,puts("");
#define FOR(i,a,b) for(ll i=(a); i<=(b); ++i)
#define ROF(i,a,b) for(ll i=(a); i>=(b); --i)
#define pb push_back
//
//
//
using namespace std;
inline ll read() {
ll f = 0, t = 0;
char c = getchar();
while (!isdigit(c)) t |= (c == '-'), c = getchar();
while (isdigit(c)) f = (f << 3) + (f << 1) + c - 48, c = getchar();
return t ? -f : f;
}
void write(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MX = 1005;
int f[30][MX][MX];
struct Link {
int x, y, w;
} h[MX * MX];
int n, m, L, C;
void push_down(int id, int l, int r) {
FOR(i,1,n) FOR(j,1,n) f[id][i][j] = f[id - 1][i][j];
FOR(k, l, r) FOR(i, 1, n) FOR(j, 1, n)
f[id][i][j] = min(f[id][i][j], min(f[id][i][h[k].x] + f[id][h[k].y][j] + h[k].w, f[id][i][h[k].y] + f[id][h[k].x][j] + h[k].w));
}
int ans2 = 0;
#define mid (l+r>>1)
const int inf = 1e18;
void solve(int id, int l, int r) {
if(l == r) {
int sum = 0;
FOR(i,1,n) FOR(j,1,n) {
if(f[id][i][j] == inf) sum += L;
else sum += f[id][i][j];
}
ans2 = max(ans2, sum);
return;
}
push_down(id + 1, l ,mid);
solve(id + 1, mid + 1, r);
push_down(id + 1, mid + 1, r);
solve(id + 1, l, mid);
}
signed main() {
while(~scanf("%lld%lld%lld",&n,&m,&L)) {
FOR(i, 1, n) FOR(j, 1, n) f[0][i][j] = inf;
FOR(i, 1, n) f[0][i][i] = 0;
FOR(i,1,m) {
int x = read(), y = read(), w = read();
h[i] = {x, y, w};
}
ans2 = 0;
push_down(1, 1, m);
int ans = 0;
FOR(i,1,n) FOR(j,1,n) {
if(f[1][i][j] == inf) ans += L;
else ans += f[1][i][j];
}
solve(0, 1, m);
cout<<ans<<" "<<ans2<<'\n';
}
return 0;
}
——end——