目录
A.POJ-2387 Til the Cows Come Home
C.POJ-1797 Heavy Transportation
前言
最短路算法主要分为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])。
这个做法空间是 。
但我们发现数组的第一维是没有用的,于是可以直接改成 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&