Loading

P2901 [USACO08MAR] Cow Jogging G (拓扑序+归并排序)

P2901 [USACO08MAR] Cow Jogging G

拓扑序+归并排序

容易看出图是有向无环图,考虑在拓扑序上维护每个点的 \(k\) 短路。假如遍历到 \(u\),有边 \((u,v,w)\)\(u\)\(v\) 各自有自己的 \(k\) 短路,我们需要将 \(u\) 上的 \(k\) 短路加 \(w\) 后与 \(v\) 上排序,然后去前 \(k\) 小。直接做是 \(O(k\log k)\) 的,但是不难想到两个有序数组可以用归并排序,这样是 \(O(k)\)

每个边都需要合并一次,复杂度 \(O(mk)\)

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e3 + 10;
int n, m, k;
std::vector<pii> e[N];
struct path {
	int p[110];
} a[N];
int b[N], c[N], ret[N];
void merge() {
	int bpos = 1, cpos = 1, rpos = 0;
	memset(ret, 0x3f, sizeof(ret));
	while(bpos <= k && cpos <= k) {
		if(b[bpos] <= c[cpos]) ret[++rpos] = b[bpos++];
		else ret[++rpos] = c[cpos++];
	}
	while(bpos <= k) ret[++rpos] = b[bpos++];
	while(cpos <= k) ret[++rpos] = c[cpos++];
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	std::cin >> n >> m >> k;
	for(int i = 1; i <= m; i++) {
		int u, v, d;
		std::cin >> u >> v >> d;
		e[u].pb({v, d});
	}

	std::queue<int> q;
	q.push(n);
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= k; j++) a[i].p[j] = iinf;
	}
	a[n].p[1] = 0;
	for(int u = n; u >= 0; u--) {
		for(auto x : e[u]) {
			int v = x.fi, w = x.se;
			bcnt = ccnt = 0;
			for(int i = 1; i <= k; i++) b[i] = a[u].p[i] + w * (a[u].p[i] != iinf);
			for(int i = 1; i <= k; i++) c[i] = a[v].p[i];
			merge();
			for(int i = 1; i <= k; i++) a[v].p[i] = ret[i];
		}
	}

	for(int i = 1; i <= k; i++) {
		std::cout << (a[1].p[i] != iinf ? a[1].p[i] : -1) << "\n"; 
	}

	return 0;
}
posted @ 2024-07-09 10:22  Fire_Raku  阅读(7)  评论(0编辑  收藏  举报