【CF 1196F】K-th Path

题意:
给出一张\(n\)个点\(m\)条边的无向图,定义\(d_{i, j}(1 \leq i < j \leq n)\)表示\(i \rightarrow j\)的最短路径,那么一共有\(\frac{n(n - 1)}{2}\)条最短路径,现在要求输出第\(k(1 \leq k \leq 400)\)短的路径长度。

思路:
考虑按权值排序后的前\(k\)条边相邻两点的距离已经能构成\(k\)条路径使得第\(k + 1\)条边的加入不会比它们短。
但是它们不一定是前\(k\)短的,但是考虑到点数最多只有\(2k\),跑\(Floyd\)即可。

代码:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
#define N 200010
int n, m, k;
struct Edge {
	int u, v, w;
	Edge() {}
	void scan() {
		scanf("%d%d%d", &u, &v, &w);
	}
	bool operator < (const Edge &other) const {
		return w < other.w; 
	}
}e[N];
struct Hash {
	int a[N], cnt;
	Hash() { cnt = 0; }
	void add(int x) {
		a[++cnt] = x;
	}
	void work() {
		sort(a + 1, a + 1 + cnt);
		cnt = unique(a + 1, a + 1 + cnt) - a - 1;
	}
	int get(int x) {
		return lower_bound(a + 1, a + 1 + cnt, x) - a;
	}
}hs;
ll f[810][810];
 
void Floyd(int n) {
	for (int k = 1; k <= n; ++k) {
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= n; ++j) {
				f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
			}
		}
	}
}
 
int main() {
	while (scanf("%d%d%d", &n, &m, &k) != EOF) {
		for (int i = 1; i <= m; ++i) e[i].scan();
		sort(e + 1, e + 1 + m);
		hs = Hash();
		for (int i = 1; i <= k; ++i) {
			hs.add(e[i].u);
			hs.add(e[i].v);
		}
		hs.work();
		memset(f, 0x3f, sizeof f);
		for (int i = 1; i <= k; ++i) {
			int u = hs.get(e[i].u);
			int v = hs.get(e[i].v);
			f[u][v] = e[i].w;
			f[v][u] = e[i].w; 
		}
		int tot = hs.cnt;
		Floyd(tot);
		vector <ll> vec;
		for (int i = 1; i <= tot; ++i)
			for (int j = i + 1; j <= tot; ++j) {
				vec.push_back(f[i][j]);
			}
		sort(vec.begin(), vec.end());
		printf("%lld\n", vec[k - 1]);
	}
	return 0;
}
posted @ 2019-07-31 08:23  Dup4  阅读(137)  评论(0)    收藏  举报