1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> PII;
const int K = 210, N = 2e3 + 5, M = 1e4 + 5; // 数据范围
int k, n, m, s, t; int he[N], tot; struct edge { int to, nxt, t, h; } e[M << 1]; // 双向边 int dis[N][K]; bool vis[N]; int ans = 0x3f3f3f3f; // 初始化成最大值,最终找到最小值
void add(int u, int v, int t, int h) { e[ ++ tot] = (edge) {v, he[u], t, h}; he[u] = tot; }
void dijkstra(int s) { memset(dis, 0x3f, sizeof dis); // 类似于普通的 Dijkstra 中的初始化 dis[s][0] = 0; priority_queue <PII, vector <PII>, greater <PII> > q; // 小根堆 q.push({0, s}); while (q.size()) { auto p = q.top(); q.pop(); int u = p.second; for (int i = he[u]; i; i = e[i].nxt) { int v = e[i].to, h = e[i].h, t = e[i].t; int minn = 0x3f3f3f3f; // 要取一个“最小值” for (int j = 0; j < k - h; j ++ ) { // 循环区间合法 if (dis[v][j + h] > dis[u][j] + t) { dis[v][j + h] = dis[u][j] + t; minn = min(minn, dis[v][j + h]); // 要在更新后的数据中找到“最小值”,以进行接下来的更新 } } if (minn != 0x3f3f3f3f) // 如果“更新成功” q.push({minn, v}); // 那么就把“最小值”放进堆里,进行接下来的更新 } } }
int main() { cin >> k >> n >> m; for (int i = 1, u, v, t, h; i <= m; i ++ ) { cin >> u >> v >> t >> h; add(u, v, t, h), add(v, u, t, h); // 建双向边 } cin >> s >> t; dijkstra(s); // 从起点开始 for (int i = 0; i < k; i ++ ) ans = min(ans, dis[t][i]); // 在 p 所有小于 k 的答案中找最小值 if (ans >= 0x3f3f3f3f / 2) // 一种技巧,即起点并不能通向终点,但终点会被其旁边的点更新 puts("-1"); // 但是又不会变小太多,所以用正无穷的一半即可完成判定 else cout << ans << endl; return 0; }
|