一.题目(牛客)
题目描述:旅行者的地图给出了高速公路沿线城市之间的距离以及每条高速公路的成本。
现在你应该写一个程序来帮助旅行者决定他/她的起始城市和目的地之间的最短路径。
如果这样的最短路径不是唯一的,那么您应该输出具有最小成本的路径,这保证是唯一的。
每个输入文件包含一个测试用例。每个案例都以包含4个正整数N,M,S和D的行开头,其中N(<= 500)是城市的数量(因此城市的编号从0到N-1); M是高速公路的数量; S和D分别是起始城市和目的地城市。然后M行跟随,每个都提供高速公路的信息,格式为:
City1 City2 Distance Cost ,
其中数字全部不超过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
输出样例
0 2 3 3 40
二.解题思路
使用邻接矩阵作为数据存储结构,用迪杰斯特拉算法求解最短路径
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int const MaxVreterNum = 500;
#define INFINITY 65535
typedef int Vertex;
typedef int WeightType;
struct Enode {//边的定义
Vertex v1, v2;
WeightType Weight;
WeightType Money;
};
typedef Enode *Edge;
struct Gnode {//图,列矩阵
int NumVex;
int NumEdge;
WeightType G[MaxVreterNum][MaxVreterNum];
WeightType M[MaxVreterNum][MaxVreterNum];
};
typedef Gnode *MGraph;
MGraph CreatGraph(int VertexNum);
void InsertEdge(MGraph Graph, Edge E);
MGraph BuildGraph(Vertex &S, Vertex &D);
Vertex FindMinDist(MGraph Graph, int dist[], int collected[]);
bool Dijkstra(MGraph Graph, int dist[], int path[], int cost[], Vertex S);
void FindThePathOut(MGraph Graph, Vertex S, Vertex D);
int main()
{
MGraph Graph;
Vertex S, D;
Graph = BuildGraph(S, D);
FindThePathOut(Graph, S, D);
return 0;
}
MGraph CreatGraph(int VertexNum)
{
MGraph Graph;
Graph = new Gnode;
Graph->NumVex = VertexNum;
Graph->NumEdge = 0;
for (Vertex v = 0; v < Graph->NumVex; v++)
{
for (Vertex w = 0; w < Graph->NumVex; ++w)
{
Graph->G[v][w] = INFINITY;
Graph->M[v][w] = INFINITY;
}
}
return Graph;
}
void InsertEdge(MGraph Graph, Edge E)
{//插入边
Graph->G[E->v1][E->v2] = E->Weight;
Graph->G[E->v2][E->v1] = E->Weight;
Graph->M[E->v1][E->v2] = E->Money;
Graph->M[E->v2][E->v1] = E->Money;
}
MGraph BuildGraph(Vertex &S, Vertex &D)
{//创建图
MGraph Graph;
Edge E;
Vertex NumVex;
cin >> NumVex;
Graph = CreatGraph(NumVex);
cin >> Graph->NumEdge >> S >> D;
if (Graph->NumEdge != 0)
{
E = new Enode;
for (int i = 0; i < Graph->NumEdge; i++)
{
cin >> E->v1 >> E->v2 >> E->Weight >> E->Money;
InsertEdge(Graph, E);
}
}
return Graph;
}
/*迪杰斯特拉算法描述:以每一个顶点为源点,重复执行迪杰斯特拉算法n次,即可求出每一对顶点之间的最短路径;
迪杰斯特拉算法主要分为三步
1.创建数据存储结构(此处为邻接矩阵)
2.函数FindMinDist()找到当前为访问顶点的最短路径;
3.此处使用栈存储,输出从目的地到出发点的最短路径;
*/
bool Dijkstra(MGraph Graph, int dist[], int path[], int cost[], Vertex S)
{
int collected[Graph->NumVex];
Vertex V;
for (V = 0; V < Graph->NumVex; ++V)
{
dist[V] = Graph->G[S][V];
cost[V] = Graph->M[S][V];
path[V] = S;
collected[V] = false;
}
dist[S] = 0;
cost[S] = 0;
collected[S] = true;
while (true)
{
V = FindMinDist(Graph, dist, collected);
if (V == -1)
break;
collected[V] = true;
for (Vertex W = 0; W < Graph->NumVex; ++W)
{
if (collected[W] == false && Graph->G[V][W] < INFINITY)
{
if (Graph->G[V][W] < 0)
return false;
if (dist[V] + Graph->G[V][W] < dist[W])
{
dist[W] = dist[V] + Graph->G[V][W];
path[W] = V;
cost[W] = cost[V] + Graph->M[V][W];
}
else if (dist[V] + Graph->G[V][W] == dist[W] && cost[V] + Graph->M[V][W] < cost[W])
{
dist[W] = dist[V] + Graph->G[V][W];
path[W] = V;
cost[W] = cost[V] + Graph->M[V][W];
}
}
}
}
return true;
}
Vertex FindMinDist(MGraph Graph, int dist[], int collected[])
{//在数据中寻找当前最短
Vertex MinVex = 0;
int MinDist = INFINITY;
for (Vertex V = 0; V < Graph->NumVex; V++)
{
if (collected[V] == false && dist[V] < MinDist)
{
MinDist = dist[V];
MinVex = V;
}
}
if (MinDist < INFINITY)
{
return MinVex;
}
else
return -1;
}
void FindThePathOut(MGraph Graph, Vertex S, Vertex D)
{//打印最短路径
int dist[Graph->NumVex];
int path[Graph->NumVex];
int cost[Graph->NumVex];
Dijkstra(Graph, dist, path, cost, S);
vector<Vertex> ThePath;
Vertex P = D;
ThePath.push_back(P);
while (P != S)
{
ThePath.push_back(path[P]);
P = path[P];
}
for (auto it = ThePath.rbegin(); it != ThePath.rend(); ++it)
cout << *it << " ";
cout << dist[D] << " " << cost[D] << endl;
}