最短路基础与习题

目录

 

前言

Floyd算法

Dijkstra算法

详解

模板

Spfa算法

详解

模板

例题

A.POJ-2387 Til the Cows Come Home

B.POJ-2253 Frogger

C.POJ-1797 Heavy Transportation

D:POJ-3268 Silver Cow Party

E:POJ-1860 Currency Exchange

F:POJ-3259 Wormholes

G.POJ-1502 MPI Maelstrom

H.POJ-3660 Cow Contest 


前言

最短路算法主要分为Floyd,Dijkstra,Spfa(由Bellman-Ford 算法优化而来),而且这三种算法都是非常重要的。最短路求值问题主要分为单源最短路与多源最短路。单源最短路即在图中求出给定顶点到其它任一顶点的最短路径,而多源最短路要在途中求出任意两个顶点的最短路径。

Floyd算法

是用来求任意两个结点之间的最短路的。复杂度比较高,但是常数小,容易实现。(我能说只有三个 for 吗?)

适用于任何图,不管有向无向,边权正负,但是最短路必须存在。(不能有个负环)

我们定义一个数组 f[k][x][y] ,表示只允许经过结点 1到 k,结点 x到结点 y的最短路长度。

很显然, f[n][x][y] 就是结点x到结点 y的最短路长度。

由此可以得到:f[k][x][y] = min(f[k-1][x][y], f[k-1][x][k]+f[k-1][k][y])。这个做法空间是  0(N^{3})

但我们发现数组的第一维是没有用的,于是可以直接改成 f[x][y] = min(f[x][y], f[x][k]+f[k][y]) .

for (k = 1; k <= n; k++) {
  for (i = 1; i <= n; i++) {
    for (j = 1; j <= n; j++) {
      f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
    }
  }
}

Dijkstra算法

Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到其他顶点的最短路径问题。举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离,Dijkstra 算法可以用来找到两个城市之间的最短路径。附上大佬的详解Dijkstra算法图文详解与我的一个模板。

详解

指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”。例如求下图中的1号顶点到2、3、4、5、6号顶点的最

短路径。

 

下面我们来模拟一下:

 这就是Dijkstra算法的基本思路。

模板

void dijkstra(int u){   //u结点到n节点的最短路
	int i,j,min1,v;
	int dis[MAXV];
	bool vis[MAXV];
	for(i=1;i<=n;i++){
		vis[i]=0;
		dis[i]=map1[u][i];
	}
        vis[u]=1;
	for(i=1;i<=n;i++){
		min1=inf;
		for(j=1;j<=n;j++)
			if(!vis[j] && dis[j]<min1){
				v=j;
				min1=d[j];
			}
		vis[v]=1;
		for(j=1;j<=n;j++)
			if(!vis[j] && dis[j]>map1[v][j]+dis[v])
				dis[j]=map1[v][j]+dis[v];
	}
	printf("%d\n",dis[n]);
}

Spfa算法

SPFA(Shortest Path Faster Algorithm)算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法。

很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。SPFA的复杂度大约是O(kE),k是每个点的平均进队次数(一般的,k是一个常数,在稀疏图中小于2)。

但是,SPFA算法稳定性较差,在稠密图中SPFA算法时间复杂度会退化。另附另一个大佬的Spfa算法图文详解与模板(谁让我不会写呢),这里只介绍下过程,证明可以参考下大佬的博客。

详解

首先建立起始点a到其余各点的最短路径表格

首先源点a入队,当队列非空时:
1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:

在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点
需要入队,此时,队列中新入队了三个结点b,c,d

2、队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:

在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要
入队,此时队列中的元素为c,d,e

3、队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:

在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此
e不用入队了,f要入队,此时队列中的元素为d,e,f

4、 队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g

5、队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:

在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e

6、队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:

在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b
7、队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:


在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b

8、队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:

在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了

最终a到g的最短路径为14

模板

void SPFA()
{
    queue&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值