解题过程的小记录,如有错误欢迎指出。
难度:三星(Dijkstra+DFS模板题,题不难,奈何我手生orz)
题目分析
给出各城市之间的距离和路过需要的花费,找出给定的起始点和终点的花费最少的最短路径,要求输出路径所经过的城市、最短距离和花费
注意点
- 采用邻接矩阵保存数据的话,距离和花费都要双重赋值,即G[u][v]=G[v][u]
我的解题过程
思路
- 先通过Dijkstra函数找出给定起点的单源最短路径,并在函数中用变长数组保存前驱们
- 再通过DFS函数走过每一条最短路径,遍历到叶子结点(起点)的时候根据第二加权项(花费),找出花费最少的路径记录在path中
bug
- Dijkstra中找未遍历过的距离最近的结点板块写错了,漏了更新MIN值
- DFS中没有把当前的结点push进tempPath中
代码
#include<iostream>
#include<vector>
using namespace std;
const int MAXV = 505;
const int INF = 1000000000;
int n, m, s, d;
int G[MAXV][MAXV], cost[MAXV][MAXV];
int dis[MAXV];
bool vis[MAXV] = { false };
vector<int> pre[MAXV], tempPath, path;
int mincost = INF;
void Dijkstra(int s) {
fill(dis, dis + MAXV, INF);
dis[s] = 0;
for (int i = 0; i < n; i++) {
int u = -1;
int MIN = INF;
for (int j = 0; j < n; j++) {
if (vis[j] == false && dis[j] < MIN) {
u = j;
MIN = dis[j];//***写错的地方,原来漏写了,MIN不赋值就找不到最小值
}
}
if (u == -1) return;
vis[u] = true;
for (int v = 0; v < n; v++) {
if (vis[v] == false && G[u][v] != INF) {
if (dis[v] > dis[u] + G[u][v]) {
dis[v] = dis[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (dis[v] == dis[u] + G[u][v]) {
pre[v].push_back(u);
}
}
}
}
}
void DFS(int end) {
if (end == s) {
tempPath.push_back(s);
int totalcost = 0;
for (int i = tempPath.size() - 1; i > 0; i--) {
int u = tempPath[i], v = tempPath[i - 1];
totalcost += cost[u][v];
}
if (totalcost < mincost) {
mincost = totalcost;
path = tempPath;
}
tempPath.pop_back();
return;
}
tempPath.push_back(end);//****写错的地方,原来写在循环里面,新增的是前驱然而本节点都没有加入到里面去
for (int i = 0; i < pre[end].size(); i++) {
DFS(pre[end][i]);
}
tempPath.pop_back();
}
int main()
{
scanf("%d %d %d %d", &n, &m, &s, &d);
fill(G[0], G[0] + MAXV*MAXV, INF);
for (int i = 0; i < m; i++) {
int u, v, len, c;
scanf("%d %d %d %d", &u, &v, &len, &c);
G[u][v] = len;
G[v][u] = len;
cost[u][v] = c;
cost[v][u] = c;
}
Dijkstra(s);
DFS(d);
for (int i = path.size() - 1; i >= 0; i--) {
printf("%d ", path[i]);
}
printf("%d %d", dis[d], mincost);
return 0;
}
dalao的代码
全部代码因版权原因不放出来,大家可以自行去柳神博客购买或者参考晴神的上机笔记~
借鉴点
本题还可以只用Dijkstra一个函数完成(在更新那里对第二权重大做文章,完整代码在晴神的算法笔记上有),个人感觉对于不需要输出路径的采用一个函数完成比较方便,对于要输出路径的或者第二权重复杂的采用Dijkstra+DFS的模板更加方便