【无标题】

最短路径

最短路径问题引入

从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径。

解决最短路径的两种算法

1.迪杰斯特拉算法(Dijkstra算法)

思路分析

迪杰特斯拉算法说白了就是一种贪心思想,比如说找到v1与v8之间的最短路径,他不是一下子就求出了v1到v8的最短路径,而是一步步求出他们顶点之间的最短路径,过程都是基于已经求出的最短路径的基础上,求得更远的顶点的最短路径,最终的得到了你最新要的结果。
简而言之就是一种贪心的思想

核心代码
void Dijkstra(MGraph G,int v0,Patharc* p,ShortPathTable* D){
	int v,w,k,min;
	int final[MAXVEX];
	for(v=0;v<G.numVertexes;v++){
		final[v] = 0;
		(*D)[v] = G.arc[v0][v];//将与v0边连接的权值加上。 
		(*p)[v] = -1;
	}
	(*D)[v0] = 0;
	final[v0] = 1;//变为说明已经求得了这点的最短路径
	for(v=1;v<G.numVertexes;v++){
		min = INFINITY;
		for(w=0;w<G.numVertexes;w++){
			if(final[w]==0&&(*D)[w]<min){
				k = w;
				min = (*D)[w];
			}
		}
		final[k] = 1;//标记找到。
		for(w=0;w<G.numVertexes;w++){//修正当前路径的最短距离 ,因为二者直接相连并不一定是最短 
			if(final[w]==0&&(min+G.arc[k][w])<(*D)[w]){
				(*D)[w] = min+G.arc[k][w];
				(*p)[w] = k;
			}
		} 
		
	}
	 
} 
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535
typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX];    /* 用于存储最短路径下标的数组 */
typedef int ShortPathTable[MAXVEX];/* 用于存储到各点最短路径的权值和 */

/* 构件图 */
void CreateMGraph(MGraph *G)
{
	int i, j;

	/* printf("请输入边数和顶点数:"); */
	G->numEdges=16;
	G->numVertexes=9;

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		G->vexs[i]=i;
	}

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		for ( j = 0; j < G->numVertexes; j++)
		{
			if (i==j)
				G->arc[i][j]=0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}

	G->arc[0][1]=1;
	G->arc[0][2]=5; 
	G->arc[1][2]=3; 
	G->arc[1][3]=7; 
	G->arc[1][4]=5; 

	G->arc[2][4]=1; 
	G->arc[2][5]=7; 
	G->arc[3][4]=2; 
	G->arc[3][6]=3; 
	G->arc[4][5]=3;

	G->arc[4][6]=6;
	G->arc[4][7]=9; 
	G->arc[5][7]=5; 
	G->arc[6][7]=2; 
	G->arc[6][8]=7;

	G->arc[7][8]=4;


	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] =G->arc[i][j];
		}
	}

}
void Dijkstra(MGraph G,int v0,Patharc* p,ShortPathTable* D){
	int v,w,k,min;
	int final[MAXVEX];
	for(v=0;v<G.numVertexes;v++){
		final[v] = 0;
		(*D)[v] = G.arc[v0][v];//将与v0边连接的权值加上。 
		(*p)[v] = -1;
	}
	(*D)[v0] = 0;
	final[v0] = 1;//变为说明已经求得了这点的最短路径
	for(v=1;v<G.numVertexes;v++){
		min = INFINITY;
		for(w=0;w<G.numVertexes;w++){
			if(final[w]==0&&(*D)[w]<min){
				k = w;
				min = (*D)[w];
			}
		}
		final[k] = 1;//标记找到。
		for(w=0;w<G.numVertexes;w++){//修正当前路径的最短距离 ,因为二者直接相连并不一定是最短 
			if(final[w]==0&&(min+G.arc[k][w])<(*D)[w]){
				(*D)[w] = min+G.arc[k][w];
				(*p)[w] = k;
			}
		} 
		
	}
	 
} 
int main(void)
{   
	int i,j,v0;
	MGraph G;    
	Patharc P;    
	ShortPathTable D; /* 求某点到其余各点的最短路径 */   
	v0=0;
	
	CreateMGraph(&G);
	
	Dijkstra(G, v0, &P, &D);  

	printf("最短路径倒序如下:\n");    
	for(i=1;i<G.numVertexes;++i)   
	{       
		printf("v%d - v%d : ",v0,i);
		j=i;
		while(P[j]!=-1)
		{
			printf("%d ",P[j]);
			j=P[j];
		}
		printf("\n");
	}    
	printf("\n源点到各顶点的最短路径长度为:\n");  
	for(i=1;i<G.numVertexes;++i)        
		printf("v%d - v%d : %d \n",G.vexs[0],G.vexs[i],D[i]);     
	return 0;
}

2.弗洛伊德算法(Floyd算法)

思路分析

1.所有点对间的最短路径
Floyd用到了动态规划的思想:求两点i、j之间的最短距离,可以分为两种情况考虑,即经过图中某个点k的路径和不经过点k的路径,取两者中的最短路径。
动态规划的过程可以描述为:
(1)令k=1,计算所有结点之间(经过结点1、不经过结点1)的最短路径。
(2)令k=2,计算所有结点之间(经过结点2、不经过结点2)的最短路径,这次计算利用了k=1时的计算结果。
(3)令k=3…
可以想象这样一个过程:
(1)图中有n个结点,m条边。
(2)把图上的每个点看成一个灯,初始时灯都是灭的,大部分结点之间的距离被初始化为无穷大INF,除了m条边连接的那些结点以外。
(3)从结点k=1开始操作,想象点亮了这个灯,并以k=1位中转点,计算和调整图上所有点之间的最短距离。很显然,对这个灯的邻居进行的计算是有效的,而对远离它的那些点的计算基本是无效的。
(4)逐步点亮所有的灯,每次点灯,就用这个灯中转,重新计算和调整所有灯之间的最短距离,这些计算用到了以前点灯时得到的计算结果。
(5)灯逐渐点亮,知道图上的点全亮,计算结束。
在这个过程中,由于很多计算都是无效的,所以算法的效率并不高。
floyd()有3重循环,复杂度是O(n^3),只能用于计算规模很小的图,即n<200的情况。

核心代码
void Floyd(MGraph G,Patharc* P,ShortPathTable* D){
	int v,w,k;
	for(v=0;v<G.numVertexes;v++){
		for(w=0;w<G.numVertexes;w++){
			(*D)[v][w] = G.arc[v][w];
			(*P)[v][w] = w;
		}
	}
	for(k=0;k<G.numVertexes;k++){
		for(v=0;v<G.numVertexes;v++){
			for(w=0;w<G.numVertexes;w++){
				if((*D)[v][w]>(*D)[v][k]+(*D)[k][w]){
					(*D)[v][w] = (*D)[v][k]+(*D)[k][w];
					(*P)[v][w] = (*P)[v][k];
				}
			}
		}
	}
}
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535
typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];

/* 构件图 */
void CreateMGraph(MGraph *G)
{
	int i, j;

	/* printf("请输入边数和顶点数:"); */
	G->numEdges=16;
	G->numVertexes=9;

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		G->vexs[i]=i;
	}

	for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
	{
		for ( j = 0; j < G->numVertexes; j++)
		{
			if (i==j)
				G->arc[i][j]=0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}

	G->arc[0][1]=1;
	G->arc[0][2]=5; 
	G->arc[1][2]=3; 
	G->arc[1][3]=7; 
	G->arc[1][4]=5; 

	G->arc[2][4]=1; 
	G->arc[2][5]=7; 
	G->arc[3][4]=2; 
	G->arc[3][6]=3; 
	G->arc[4][5]=3;

	G->arc[4][6]=6;
	G->arc[4][7]=9; 
	G->arc[5][7]=5; 
	G->arc[6][7]=2; 
	G->arc[6][8]=7;

	G->arc[7][8]=4;


	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] =G->arc[i][j];
		}
	}

}
void Floyd(MGraph G,Patharc* P,ShortPathTable* D){
	int v,w,k;
	for(v=0;v<G.numVertexes;v++){
		for(w=0;w<G.numVertexes;w++){
			(*D)[v][w] = G.arc[v][w];
			(*P)[v][w] = w;
		}
	}
	for(k=0;k<G.numVertexes;k++){
		for(v=0;v<G.numVertexes;v++){
			for(w=0;w<G.numVertexes;w++){
				if((*D)[v][w]>(*D)[v][k]+(*D)[k][w]){
					(*D)[v][w] = (*D)[v][k]+(*D)[k][w];
					(*P)[v][w] = (*P)[v][k];
				}
			}
		}
	}
}
int main(void)
{    
	int v,w,k;  
	MGraph G;    
	
	Patharc P;    
	ShortPathTable D; /* 求某点到其余各点的最短路径 */   
	
	CreateMGraph(&G);
	
	Floyd(G,&P,&D);  

	printf("各顶点间最短路径如下:\n");    
	for(v=0; v<G.numVertexes; ++v)   
	{        
		for(w=v+1; w<G.numVertexes; w++)  
		{
			printf("v%d-v%d weight: %d ",v,w,D[v][w]);
			k=P[v][w];				/* 获得第一个路径顶点下标 */
			printf(" path: %d",v);	/* 打印源点 */
			while(k!=w)				/* 如果路径顶点下标不是终点 */
			{
				printf(" -> %d",k);	/* 打印路径顶点 */
				k=P[k][w];			/* 获得下一个路径顶点下标 */
			}
			printf(" -> %d\n",w);	/* 打印终点 */
		}
		printf("\n");
	}

	printf("最短路径D\n");
	for(v=0; v<G.numVertexes; ++v)  
	{        
		for(w=0; w<G.numVertexes; ++w)    
		{
			printf("%d\t",D[v][w]);
		}
		printf("\n");
	}
	printf("最短路径P\n");
	for(v=0; v<G.numVertexes; ++v)  
	{        
		for(w=0; w<G.numVertexes; ++w)    
		{
			printf("%d ",P[v][w]);
		}
		printf("\n");
	}

	return 0;
}

总而言之,两种算法都很优秀,希望大家掌握。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值