有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第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
题目思路:
1.我是参考《算法笔记》胡凡老师的书中的Dijkstra算法的讲解将题目解出来的,在pta上后三个测试点一直错,后来发现是建图的过程中我建造的是有向图,他因该是双向的一个过程。
2.这道题就是加了边权的Dijkstra算法,就是在Dijkstra算法基础上进行的灵活应用。
3.关于Dijkstra算法,我个人的理解是,遍历n个顶点,每次找到权值最小的那个顶点,然后以该顶点作为中介,找到下一条最短边,并使用d数组记录下来。
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1005;
const int INF = 0x3f3f3f;
int n, m, s, ter, Graph[MAXN][MAXN];
int d[MAXN]; //当前顶点到起点的最短路径长度
int c[MAXN]; //当前顶点到起点的花费
int cost[MAXN][MAXN]; //两个顶点间的花费
bool Visited[MAXN]; //访问标志数组
void Dijkstra(int s);
int main()
{
fill(Graph[0], Graph[0] + MAXN * MAXN, INF);
fill(cost[0], cost[0] + MAXN * MAXN, INF); //初始化
int u, v, w, x;
cin >> n >> m >> s >> ter;
while (m--) //建图
{
cin >> u >> v >> w >> x;
Graph[u][v] = Graph[v][u] = w; //记住这道题问的是无向图,建立的时候是双向的
cost[u][v] = cost[v][u] = x;
}
Dijkstra(s);
cout << d[ter] << " " << c[ter]; //输出terminal顶点到起点的最短路径长度和最少花费
return 0;
}
void Dijkstra(int s)
{
fill(d, d + MAXN, INF);
fill(c, c + MAXN, INF);
d[s] = 0;
c[s] = 0; //以上四条语句均为初始化
for (int i = 0; i < n; i++) //循环n次
{
int u = -1, MIN = INF;
for (int j = 0; j < n; j++) //查找权值最小的边
if (!Visited[j] && d[j] < MIN) //寻找未被访问顶点中最小d[]
{
u = j;
MIN = d[j];
}
if (u == -1) return; //如果找不到小于INF,说明剩下的点不连通
Visited[u] = true; //标记
for (int v = 0; v < n; v++) //以找到的u作为连接下一个顶点v的中介点
if (!Visited[v] && Graph[u][v] != INF)
{
if (d[u] + Graph[u][v] < d[v]) //下一条权值小的边
{
d[v] = d[u] + Graph[u][v]; //更新权值
c[v] = c[u] + cost[u][v]; //更新费用
}
else if (d[u] + Graph[u][v] == d[v] && c[u] + cost[u][v] < c[v])//路径相同,但费用变小则需要更新
c[v] = c[u] + cost[u][v];
}
}
}