题解:P3096 [USACO13DEC] Vacation Planning G
本题:P3096 [USACO13DEC] Vacation Planning G\ 弱化版:P3094 [USACO13DEC] Vacation Planning S
思路
其实就是 Dijkstra 的模板题。
题目意思简化为:
给定一张
思路:
弱化版:由于数据量非常小,
本题:由于数据量比较大,使 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;
}