日期:2023.10.18
第8天
题目来源:patA1030
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int n, m, s, d;
const int INF = 0x3f3f3f3f;
const int MAXN = 510;
int G[MAXN][MAXN];
int dijk[MAXN];
int vis[MAXN] = {0};
int cost[MAXN][MAXN];//路上的消耗
vector<int> pre[MAXN];
int totalDis = 0 , totalCost = INF;
vector<int> path, tempPath;
//找出每个点的最短路径
void Dijkstra(int s) {
memset(dijk, 0x3f, sizeof(dijk));
dijk[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, MIN = INF;
//找到非集合S中距离起点最近的点
for(int j = 0; j < n; j++) {
if(vis[j] == 0 && dijk[j] < MIN) {
u = j;
MIN = dijk[j];
}
}
if(u == -1) return ;
//将找出来的点加入集合S
vis[u] = 1; //这一步容易忘记
//更新非集合S中的长度,记录路径
for(int v = 0; v < n; v++) {
if(G[u][v] != INF && vis[v] == 0) {
if(dijk[u] + G[u][v] < dijk[v]) {
dijk[v] = dijk[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if(dijk[u] + G[u][v] == dijk[v]) {
pre[v].push_back(u);
}
}
}
}
}
//找出最短路径中,第二标尺最优的
void DFS(int v) {
if(v == s) {
tempPath.push_back(v);
//计算当前路径上的花费
int tempCost = 0;
for(int i = tempPath.size() - 1; i > 0; i--) {
int id = tempPath[i], idNext = tempPath[i-1];
tempCost += cost[id][idNext];
}
if(tempCost < totalCost) {
totalCost = tempCost;
path = tempPath;
}
tempPath.pop_back();
return ;
}
tempPath.push_back(v);
for(int i = 0; i < pre[v].size(); i++) {
DFS(pre[v][i]);
}
tempPath.pop_back();
}
int main(void) {
scanf("%d%d%d%d", &n, &m, &s, &d);
//边进行初始化
memset(G, 0x3f, sizeof(G));
for(int i = 0; i < m; i++) {
int v1, v2, dis, c;
scanf("%d%d%d%d", &v1, &v2, &dis, &c);
G[v1][v2] = G[v2][v1] = dis;
cost[v1][v2] = cost[v2][v1] = c;
}
Dijkstra(s);
DFS(d);
for(int i = path.size() - 1; i >= 0; i--) {
printf("%d ", path[i]);
}
printf("%d %d", dijk[d], totalCost);
return 0;
}
问题:
1.牢记Dijkstra算法的三步骤;
a.将非集合S中距离起点最近的找出来;
b.将该点加入到集合S;
c.更新非集合S中的点到起点的距离;
第二步容易忘记,vis[v] = 1;
2.其实Dijkstra+DFS对复杂题更有用,如果只有一个第二标尺,完全可以直接用Dijkstra处理,这样更方便更快;