1 条题解
-
0
自动搬运
来自洛谷,原作者为

Ak_hjc_using
帅就一个字,我只说一次搬运于
2025-08-24 21:45:16,当前版本为作者最后更新于2024-12-16 18:12:56,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
本题:P3096 [USACO13DEC] Vacation Planning G
弱化版:P3094 [USACO13DEC] Vacation Planning S思路
其实就是 Dijkstra 的模板题。
题目意思简化为:
给定一张 个点, 条边的无向图, 个关键点,给定 次询问,每次询问从 到 必须经过至少一个关键点的最短路径。
思路:
弱化版:由于数据量非常小,,故直接 floyd 算出所有点的最短路径,枚举所有中转点(也就是关键点),算出答案即可。
本题:由于数据量比较大,使 floyd 无法通过本题,所有我们可以使用 Dijkstra 算法,时间复杂度稳定 ,可以过本题。
如果是使用 Dijkstra 算法,那么中转点怎么记录呢?,设有一条路径,
1 -> 2 -> 3,其中 是关键点,那么这条路径就可以化为1 -> 2的路径,加上2 -> 3的路径,那么就巧妙地转化了中转点的问题,对每一个关键点进行 Dijkstra,记录两个数组,分别用来记录 到关键点的距离和关键点到 的距离,统计答案时相加即可。重点(需要优化的地方)
我们不是记录了两个二维数组吗?但是这样的话,由于 ,所以导致空间复杂度太高了,超过了内存限制,但是发现这里的 非常小,所有我们可以把所有的关键点转换为它们各自的编号,用一个数组记录即可。
代码:
#include <iostream> #include <vector> #include <queue> #define int long long using namespace std; const int N = 2e4 + 5, M = 800; int n, m, k, q, dis_1[M][N], vis[N]; int dis_2[M][N], u[N], v[N], w[N], flag[N], val[N]; const int INF = 1e18; struct Edge { int v; int w; }; struct Node { int id, w; bool operator < (const Node &a) const { return w > a.w; } }; vector<Edge> G[N]; void add_edge(int u, int v, int w) { G[u].push_back({v, w}); return ; } void Dijkstra(int *dis, int s) { for (int i = 1; i <= n; i++) { dis[i] = INF; vis[i] = 0; } priority_queue<Node> Q; Q.push({s, 0}); dis[s] = 0; while (!Q.empty()) { Node u = Q.top(); Q.pop(); if (vis[u.id] == true) continue ; vis[u.id] = true; for (int i = 0; i < G[u.id].size(); i++) { int v = G[u.id][i].v, w = G[u.id][i].w; if (vis[v] == false && dis[v] > dis[u.id] + w) { dis[v] = dis[u.id] + w; Q.push({v, dis[v]}); } } } return ; } signed main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin >> n >> m >> k >> q; for (int i = 1; i <= m; i++) cin >> u[i] >> v[i] >> w[i]; for (int i = 1; i <= k; i++) { cin >> val[i]; flag[val[i]] = i; } for (int i = 1; i <= m; i++) add_edge(u[i], v[i], w[i]); for (int i = 1; i <= k; i++) Dijkstra(dis_1[i], val[i]); for (int i = 1; i <= n; i++) G[i].clear(); for (int i = 1; i <= m; i++) add_edge(v[i], u[i], w[i]); for (int i = 1; i <= k; i++) Dijkstra(dis_2[i], val[i]); for (int i = 1; i <= n; i++) G[i].clear(); int cnt = 0, sum = 0; while (q --) { int s, t; cin >> s >> t; int ans = 1e18; if (flag[s]) ans = dis_1[flag[s]][t]; if (flag[t]) ans = min(ans, dis_2[flag[t]][s]); if (ans == 1e18) { for (int i = 1; i <= k; i++) ans = min(ans, dis_1[i][t] + dis_2[i][s]); } if (ans != 1e18) { cnt ++; sum += ans; } } cout << cnt << '\n' << sum << endl; return 0; }
- 1
信息
- ID
- 2160
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者