一、题目大意
- PAT A1030
- 有 N 个城市,M 条道路,并给出 M 条道路的距离和花费。现给定起点 S 和终点 D,求从起点到终点的最短路径、最短距离和花费。如果有多条最短路径,则选择花费最小的那条。
二、解题思路
- 本题除了求最短距离外,还要求额外的两个信息:最短路径以及最短路径上的总花费,这里使用了 Dijkstra + DFS 算法,首先求出所有可能最短路径,然后用 DFS 递归求出花费最小的最短路径。
三、参考代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 505;
const int INF = 1000000000;
int N, M, S, D;
int dis[maxn][maxn], cost[maxn][maxn];
bool vis[maxn] = { false };
int d[maxn];
vector <int> pre[maxn], min_path, temp_path;
int min_cost = INF;
void dijkstra() {
fill(d, d + maxn, INF);
d[S] = 0;
for (int i = 0; i < N; i++) {
int u = -1, min = INF;
for (int j = 0; j < N; j++)
if (!vis[j] && d[j] < min) {
u = j;
min = d[j];
}
if (u == -1) return;
vis[u] = true;
for (int v = 0; v < N; v++) {
if (!vis[v] && dis[u][v] != INF) {
if (d[u] + dis[u][v] < d[v]) {
d[v] = d[u] + dis[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (d[u] + dis[u][v] == d[v])
pre[v].push_back(u);
}
}
}
}
void DFS(int v) {
if (v == S) {
temp_path.push_back(v);
int temp_cost = 0;
for (int i = temp_path.size() - 1; i > 0; i--) {
int id = temp_path[i];
int id_next = temp_path[i - 1];
temp_cost += cost[id][id_next];
}
if (temp_cost < min_cost) {
min_cost = temp_cost;
min_path = temp_path;
}
temp_path.pop_back();
return;
}
temp_path.push_back(v);
for (int i = 0; i < pre[v].size(); i++)
DFS(pre[v][i]);
temp_path.pop_back();
}
int main() {
cin >> N >> M >> S >> D;
fill(dis[0], dis[0] + maxn * maxn, INF);
fill(cost[0], cost[0] + maxn * maxn, INF);
for (int i = 0; i < M; i++) {
int c1, c2, d, c;
cin >> c1 >> c2 >> d >> c;
dis[c1][c2] = dis[c2][c1] = d;
cost[c1][c2] = cost[c2][c1] = c;
}
dijkstra();
DFS(D);
for (int i = min_path.size() - 1; i >= 0; i--)
cout << min_path[i] << ' ';
cout << d[D] << ' ' << min_cost << endl;
return 0;
}
四、解题感悟
- 本题求的是总边权而不是总点权,所以最后计算最短路径上的花费时,注意当前点 id 和下一个点 id_next 的使用。