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——

posted @ 2024-10-17 14:23  Sirkey  阅读(5)  评论(0编辑  收藏  举报