旅游规划 (25分)【C语言】Dijkstra算法

习题讲解视频

题目:

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式

输入说明:输入数据的第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);
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值