目录
题目:
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式
输入说明:输入数据的第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
算法
Dijkstra算法
- 贪心算法(每次从dist中选择未收集到collected中的最小值minDist)
- 当minDist使未收录的邻结点dist值更小时,更新邻结点的dist值,fee值
- 当minDist使未收录的邻结点dist值更新相等时,检查fee(初始点S到每个结点的费用),如果fee也更小,则开始更新
代码实现
#define Infinite 65535
#define VERTEXMAXNUM 500
int S,D;
int main()
{
int N,M;
scanf("%d %d %d %d",&N,&M,&S,&D);//N为城市个数,M为公路条数,S为出发城市(全局变量),D为到达城市(全局变量)
Graph G=CreateGraph(N);
BuildGraph(G,M);
Dijstra(G);
return 0;
}
Dijstra函数
- 贪心算法(每次从dist中选择未收集到collected中的最小值minDist)
- 当minDist使未收录的邻结点dist值更小时,更新邻结点的dist值,fee值
- 当minDist使未收录的邻结点dist值更新相等时,检查fee(初始点S到每个结点的费用),如果fee也更小,则开始更新
void Dijstra(Graph G)
{
int dist[VERTEXMAXNUM];//s到每个结点的最短路径长度
int fee[VERTEXMAXNUM];//s到每个结点的费用
bool collected[VERTEXMAXNUM];
int i;
{//S邻结点的dist值和fee初始化为图中相应值,其他均为Infinite(无穷)
for(i=0;i<G->VertexNum ;i++){
dist[i]=Infinite;
fee[i]=Infinite;
collected[i]=false;
}
for(i=0;i<G->VertexNum ;i++){
if(G->Matrix[S][i].Length <Infinite){
dist[i]=G->Matrix[S][i].Length;
fee[i]=G->Matrix[S][i].Fee;
}
}
}
collected[S]=true;//S结点初始化
dist[S]=0;
fee[S]=0;
int minDist=-1;
while(1){
minDistVertex=FindMinDistVertex(dist,collected,G->VertexNum );//每次从dist中选择未收集到collected中的最小值minDist的结点
if(minDistVertex==D)break;
collected[minDistVertex]=true;
for(i=0;i<G->VertexNum;i++){
if(collected[i]==true)continue;
if(dist[minDistVertex]+G->Matrix[minDistVertex][i].Length<dist[i]){//dist值可以更小时,直接更新dist和fee
dist[i]=dist[minDistVertex]+G->Matrix[minDistVertex][i].Length;
fee[i]=fee[minDistVertex]+G->Matrix[minDistVertex][i].Fee;
}else if(dist[minDistVertex]+G->Matrix[minDistVertex][i].Length==dist[i]){//dist值相等时,检查fee
if(fee[minDistVertex]+G->Matrix[minDistVertex][i].Fee<fee[i]){
dist[i]=dist[minDistVertex]+G->Matrix[minDistVertex][i].Length;
fee[i]=fee[minDistVertex]+G->Matrix[minDistVertex][i].Fee;
}
}
}
}
printf("%d %d",dist[D],fee[D]);
}
FindMinDistVertex函数:每次从dist中选择未收集到collected中的最小值minDist的结点
int FindMinDistVertex(int dist[],bool collected[],int N)
{
int i;
int MinDist=Infinite;
int vertex=-1;
for(i=0;i<N;i++){
if(MinDist>dist[i]&&(collected[i]==false)){
MinDist=dist[i];
vertex=i;
}
}
return vertex;
}
其他函数
- Graph CreateGraph(int N):建图
- void InsertEdge(Edge L,Graph G):图G中插入边L
- void BuildGraph(Graph G,int M):图G中根据边总数M插入边
typedef struct Node{
int Length;
int Fee;
}AdjMatrix[VERTEXMAXNUM][VERTEXMAXNUM];
typedef struct GNode* Graph;
struct GNode{
int VertexNum;
int EdgeNum;
AdjMatrix Matrix;
};
typedef struct ENode* Edge;
struct ENode{
int V;
int W;
int Length;
int Fee;
};
Graph CreateGraph(int N)
{
Graph G=(Graph)malloc(sizeof(struct GNode));
G->VertexNum=N;
int i=0,j=0;
for(i=0;i<N;i++){
for(j=0;j<N;j++){
G->Matrix[i][j].Fee =Infinite;
G->Matrix[i][j].Length =Infinite;
}
}
return G;
}
void InsertEdge(Edge L,Graph G)
{
G->Matrix [L->V ][L->W ].Length=L->Length ;
G->Matrix [L->V ][L->W ].Fee=L->Fee ;
G->Matrix [L->W ][L->V ].Length=L->Length ;
G->Matrix [L->W ][L->V ].Fee=L->Fee ;
}
void BuildGraph(Graph G,int M)
{
int i=0;
G->EdgeNum=M;
Edge L=(Edge)malloc(sizeof(struct ENode));
for(i=0;i<M;i++){
scanf("%d %d %d %d",&(L->V),&(L->W ),&(L->Length ),&(L->Fee ));
InsertEdge(L,G);
}
}