https://pintia.cn/problem-sets/15/problems/717
数据结构与算法题目集(中文)--> 编程题 --> 7-9
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
3 40
算法思路:普通的单源最短路径算法(改造一下即可),只不过G[ i ][ j ] 不单单要存长度,还要存一个花费,所以采用邻接矩阵,不过里面存的是pair,first存距离,second存花费。
#include<bits/stdc++.h>
using namespace std;
const int INF = INT_MAX-10;
//dijkstra
vector<int> dist;
vector<int> cost;
vector<bool> vis;
vector<vector<pair<int, int>>> G;
int n, m, s, d;
void dijkstra(int s)
{
//初始化
dist[s] = 0;
cost[s] = 0;
vis[s] = true;
//开始dp
int v = s;
int w;
while (v != d)
{
for (unsigned int i = 0; i < G[v].size(); i++)
{
w = i;
int dis = G[v][i].first;
int cos = G[v][i].second;
if (dis==INF) continue;
if (!vis[w]) //未被访问过
{
if (dist[v] + dis < dist[w])
{
dist[w] = dist[v] + dis;
cost[w] = cost[v] + cos;
}
else if (dist[v] + dis == dist[w])
{
if (cost[v] + cos < cost[w])
cost[w] = cost[v] + cos;
}
}
}
//更新v,未收录顶点中dist最小者,可以使用堆优化
//本题一定存在解,所以没有判断这样的v不在的情况,如果不存在也就是v或者minDis没有更新,那么直接break即可
int minDis = INF;
for (int i = 0; i < n; i++)
{
if (dist[i] < minDis && !vis[i]) //注:!vis[i]
{
minDis = dist[i];
v = i; //更新 v
}
}
vis[v] = true; //以新的v为起点。将其标记为true
}//while
}
int main() {
cin >> n >> m >> s >> d;
dist = vector<int>(n,INF);
cost = vector<int>(n, INF);
vis = vector<bool>(n, false);
G = vector<vector<pair<int, int>>>(n, vector<pair<int, int>>(n, {INF,INF}));
int x, y, len, val;
for (int i = 0; i < m;i++) {
cin >> x >> y >> len >> val;
G[x][y].first = len;
G[x][y].second = val;
G[y][x].first = len;
G[y][x].second = val;
}
dijkstra(s);
cout << dist[d] << " " << cost[d] << endl;
system("pause");
return 0;
}
//推荐这个版本写法
#include<bits/stdc++.h>
using namespace std;
const int INF = INT_MAX - 10;
void dijkstra(vector<vector<pair<int, int>>>& g, vector<int>& dist, vector<int>& cost, int s, int d) {
int n = g.size();
vector<bool> collected(n, false);
int v, w;
//初始化
for (v = 0; v < n; v++) {
dist[v] = g[s][v].first;
cost[v] = g[s][v].second;
}
//收录s
collected[s] = true;
dist[s] = 0;
cost[s] = 0;
v = s;
while (v!=d) {
//v=未收录顶点中dist最小者
int tmp = INF;
for (int i = 0; i < n; i++) {
if (!collected[i]) {
if (dist[i] < tmp) {
tmp = dist[i];
v = i;
}
}
}
collected[v] = true;
//对图中每个点w进行操作
for (w = 0; w < n; w++) {
if (!collected[w] && g[v][w].first != INF) {
if (dist[v] + g[v][w].first < dist[w]) {
dist[w] = dist[v] + g[v][w].first;
cost[w] = cost[v] + g[v][w].second;
}
else if (dist[v] + g[v][w].first == dist[w]) {
if (cost[v] + g[v][w].second < cost[w]) {
cost[w] = cost[v] + g[v][w].second;
}
}
}
}
}
}
int main() {
int N, M, S, D;
cin >> N >> M >> S >> D;
vector<vector<pair<int, int>>> g(N, vector<pair<int, int>>(N, {INF,INF}));
int v, w, l, c;
for (int i = 0; i < M; i++) {
cin >> v >> w >> l >> c;
g[v][w].first = l;
g[v][w].second = c;
g[w][v].first = l;
g[w][v].second = c;
}
vector<int> dist(N, INF);
vector<int> cost(N, INF);
dijkstra(g, dist, cost, S, D);
cout << dist[D] << " " << cost[D] << endl;
system("pause");
return 0;
}