题目要求:
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径
输出格式:
输入说明:输入数据的第 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
题解:
思路如注释所示,可通过所有测试点。
#include<bits/stdc++.h>
using namespace std;
#define MaxVertexNum 500 //最大顶点数
#define INFINITY 65535
#define ERROR -1
typedef int Vertex; //顶点类型为整形
typedef int WeightType; //权值为整形
typedef struct ENode *PtrToENode; //边结点
struct ENode {
Vertex V1, V2; //有向边<V1,V2>
WeightType Weight; //权重
WeightType cost; //收费额
};
typedef PtrToENode Edge;
typedef struct GNode *PtrToGNode; //存储图
struct GNode {
int Nv; //顶点数
int Ne; //边数
WeightType G[MaxVertexNum][MaxVertexNum];
WeightType Cost[MaxVertexNum][MaxVertexNum];
};
typedef PtrToGNode MGraph; //邻接矩阵存储图
Vertex start, final;
MGraph CreateGraph(int VertexNum) {
Vertex V, W;
MGraph Graph;
Graph = (MGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
for (V = 0; V < Graph->Nv; V++)
for (W = 0; W < Graph->Nv; W++) {
Graph->G[V][W] = INFINITY;
Graph->Cost[V][W] = INFINITY;
}
return Graph;
}
void InsertEdge(MGraph Graph, Edge E) {
// 因为是无向图插入<V1,V2>,<V2,V1>
Graph->G[E->V1][E->V2] = E->Weight;
Graph->Cost[E->V1][E->V2] = E->cost;
Graph->G[E->V2][E->V1] = E->Weight;
Graph->Cost[E->V2][E->V1] = E->cost;
}
MGraph BuildGraph() {
MGraph Graph;
Edge E;
int Nv, i;
cin >> Nv;
Graph = CreateGraph(Nv);
cin >> Graph->Ne; // 读入边数
cin >> start >> final; // 读入起点和终点
if (Graph->Ne != 0) {
E = (Edge)malloc(sizeof(struct ENode));
for (i = 0; i < Graph->Ne; i++) {
cin >> E->V1 >> E->V2 >> E->Weight >> E->cost;
InsertEdge(Graph, E);
}
}
return Graph;
}
Vertex FindMinDist(MGraph Graph, int dist[], int collected[]) {
Vertex MinV = ERROR;
int MinDist = INFINITY;
for (Vertex V = 0; V < Graph->Nv; V++) {
if (collected[V] == 0 && dist[V] < MinDist) {
MinDist = dist[V];
MinV = V;
}
}
return MinV;
}
void Dijkstra(MGraph Graph, int cost[], int dist[], Vertex S) {
int collected[MaxVertexNum] = { 0 };
Vertex V, W;
// 初始化dist和cost数组,若不存在边则初始化为INFINITY
for (V = 0; V < Graph->Nv; V++) {
dist[V] = Graph->G[S][V];
cost[V] = Graph->Cost[S][V];
collected[V] = 0;
}
// 初始化起始结点
dist[S] = 0;
cost[S] = 0;
collected[S] = 1;
while (1) {
// V是未被收录顶点中dist最小者
V = FindMinDist(Graph, dist, collected);
if (V == ERROR) // 所有结点都处理完
break; // 算法结束
collected[V] = 1;
for (W = 0; W < Graph->Nv; W++) {
if (collected[W] == 0 && Graph->G[V][W] < INFINITY) {
if (dist[V] + Graph->G[V][W] < dist[W]) {
dist[W] = dist[V] + Graph->G[V][W];
cost[W] = cost[V] + Graph->Cost[V][W];
} else if (dist[V] + Graph->G[V][W] == dist[W] &&
cost[V] + Graph->Cost[V][W] < cost[W]) {
cost[W] = cost[V] + Graph->Cost[V][W];
}
}
}
}
return; // 算法结束
}
int main() {
MGraph Graph = BuildGraph();
int dist[MaxVertexNum], cost[MaxVertexNum]; // dist, cost数组为起点到一个结点的路程和花费
Dijkstra(Graph, cost, dist, start);
cout << dist[final] << " " << cost[final];
return 0;
}
总结:
1.用cost和dist数组记录从起始点到一个结点的花费和距离
2.此题主要用到dijkstra算法,找到从一个结点到另一个结点的最短路径,再此基础上加入了价格这个衡量标准,所以在buildgraph时要把每条边之间的价格记录下来,当算法找到同样短的路径时,选择花费较少的那条路径