图的最短路径(dijkstra算法)

洛谷有题

P3371 【模板】单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

先放大佬的ac代码(请看第一篇题解,写的很不错!)

P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Floyd算法是求任意两点的最短路径

(5条消息) 《算法笔记》—— 图 "最短路径" 之 Floyd-Warshall算法、Diljkstra算法_浪子花梦-CSDN博客

dijkstra手工 

 

邻接矩阵方法

考试必要理解的diljkstra(模板),老师给的

/* 
* 单源最短路径,Dijkstra算法,邻接矩阵形式,复杂度为O(n^2) 
* 求出源beg到所有点的最短路径,传入图的顶点数,和邻接矩阵cost[][],n为结点个数
* 返回各点的最短路径dist[], 路径path[].path[i]记录beg到i路径上的父结点,path[beg]=-1 
* 可更改路径权类型,但是权值必须为非负 
* 
*/ 
const int MAXN=1010; 
#define typec int 
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大 
bool vis[MAXN]; //判断顶点所属集合标志数组

int  path[MAXN]; //双亲数组 记录路径
void Dijkstra(typec cost[][MAXN],typec dist[],int n,int beg) 
{ 
	for(int i=0;i<n;i++)     //初始化,使得每一条路径最大,n为顶点数
	{ 
		dist[i]=INF;
        vis[i]=false;      //这个数组记录未被访问的结点,后续判断要用
        path[i]=-1; 
	} 
	dist[beg]=0;    //起点到起点路径为0 
	
    
    for(int j=0;j<n;j++) //
	{ 
		int k=-1; 
		int Min=INF; 
		for(int i=0;i<n;i++) //先找出最小的未访问的最小顶点k
			if(!vis[i]&&dist[i]<Min) 
			{ 
				Min=dist[i]; //一直循环找最小
				k=i; 
			} 

		if(k==-1)  //如果把所有的dist遍历一遍都找到了最短路径,则退出循环结束
           break; 

		vis[k]=true; //将新找到的当前最小结点设置为“已访问”

        /*
        此时将当前最小结点置入dist后,更新所有从k结点出发到任意一顶点的路径(松弛),
        这时候可以把下一个结点的最短路径求出
        */
		for(int i=0;i<n;i++) 
		    if(!vis[i] && dist[k]+cost[k][i]<dist[i]) //松弛
		    { 
			    dist[i]=dist[k]+cost[k][i]; 
			    path[i]=k;    //每次可以通过这个pre找到上一个最短路径从而接上去
		    } 
	} 

怎么打印路径以及邻接表的dijikstra算法在下面的一个博客可以找到答案

Dijkstra算法打印路径+邻接表

(5条消息) Dijkstra基于邻接表算法C++实现_优雅~天宫雁-CSDN博客

———————————————————————————————————————————更新:偶然在书上看到了如何打印path的方法,特意写出来


template<class T , class E>
void printShotestPath(Graph<T,E>& G,int beg,E dist[],int path[]){
	cout<<"从顶点"<<G.getValue(beg)<<"到其他顶点的最短路径为:"<<endl;
	int i,j,k;
	int n=G.NumberOfVertices();    //获取顶点个数!
	int *d=new int[n];    //开辟临时存放路径的容器
	for(i=0;i<n;i++){    //对每一个dist结点进行遍历
		if(i!=beg){        //其实这个if可以省略,改动for循环从1开始
			j=i;k=0;     //k记录路径通过多少个结点,每次循环都会重置一次
			while(j!=v){    //当j=v时,则找结点找回到路径起点,结束循环
				d[k++]=j;    
				j=path[j];
			}
             
            //正常输出结点,注意是逆序                       
			cout<<"顶点"<<G.getValue(i)<<"的最短路径为:"<<G.getValue(beg);
			while(k>0){
				cout<<G.getValue(d[--k])<<" ";
			}
			cout<<"最短路径长度为:"<<dist[i]<<endl;
		}
	}
	delete []d;
};

弗洛伊德算法求最短路径

(11条消息) 弗洛伊德(Floyd)算法求图的最短路径_刘剑峰的博客-CSDN博客_floyd算法求最短路径

//这里是弗洛伊德算法的核心部分 
    //k为中间点 
    for(k = 0; k < G.vexnum; k++){
        //v为起点 
        for(v = 0 ; v < G.vexnum; v++){
            //w为终点 
            for(w =0; w < G.vexnum; 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];//更新最小路径中间顶点 ,打印路径要用
                }
            }
        }
    }

 求路径

    v = 0;
    w = 3;
    //求 0 到 3的最小路径
    printf("\n%d -> %d 的最小路径为:%d\n", 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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值