图的传递闭包算法,判断i与j是否有路径:
for (int k=1;k<=n;k++) //也可以说是Floyd的思想这是用邻接矩阵写的
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if(can[i][k] && can[k][j])can[i][j]=1;
Floyd
计算图中每对顶点(任意两点)之间的最短路径 代码如下
Floyd1:
for (int k=1;k<=n;k++)//遍历每对点
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (d[i][k]+d[k][j]<d[i][j])d[i][j]=d[i][k]+d[k][j]
/*初始化条件: D[ i][ i ]=0 自己到自己为0 对角线为0;
D[i][j]=边权,i与j有直接相连的边
D[i][j]= +∞ ,i与j无直接相连的边。因为要找最小路径啊*/
Floyd2:
//设path[i][j] 记录i到j的最短路径中j的前驱顶点。
//初始化:i到j有边
path[i][j]:=i;
path[j][i] :=j
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (d[i][k]+d[k][j]<d[i][j] )
{
d[i][j]=d[i][k]+d[k][j];
path[i][j]=path[k][j]
}
Floyd3:
//初始化:
path[i][j]= -1: //i与j不通的
path[i][j]:=0; //从i到j的最短路径是直接到达的。开始有边的都直接到达。
Path[i][j]>0;//从i到j的最短路径要经过点path[i,j].
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (d[i][k]+d[k][j]<d[i][j] )
{
d[i][j]=d[i][k]+d[k][j];
path[i][j]=k;
}
dijkstra
计算某一顶点到其它所有顶点的最短路径
若在处理过程中,有两点x、y出现不符合“三角形定理”(若连接必定存在dis[x] + len[x][y] >= dis[y] )或者说出现松弛,则可改进一下:
if ( dis[x]+len[x][y] < dis[y] )dis[y] = dis[x]+len[x][y];
dis点x到s的最短距离 len是x,y的距离
d[i]:顶点i到start的最短距离。
具体思路:假设有两组集合1 集合2。若在处理过程中,有两点x、y出现不符合“三角形定理”()或者说出现松弛,则可改进一下: if ( dis[x]+len[x][y] < dis[y])dis[y] = dis[x]+len[x][y]; d[i]:顶点i到start的最短距离。 具体思路:假设有两组集合1 集合2。我们把集合一看成一个整体,或者说已经探查清楚的区域,把集合二看成未探知的区域,(战争迷雾 括弧笑)可以假设是离散的,因为要一个一个点录入。从集合二找出离集合一最近的点,并从集合二移到集合一,这次检查集合二,看集合二中的点在该点加入集合一后,离集合一的距离有没有变短。重复这个过程,直到集合二没有点。 代码如下:
void dijkstra(int st);
{
for (int i=1;i<=n;i++) dis[i]=a[st][i];
memset(f,false,sizeof(f));
f[st]=true;
dis[st]=0;
for (int i=1;i<n;i++)
{
int min=1000000000, k=0;
for (int j=1;j<=n;j++)
if (!f[j] &&(dis[j]<min))
min=dis[j],k=j;
if (k==0) return; //已经找不到了。
f[k]=true; //把k加入集合1;
for (int j=1;j<=n;j++) //三角形迭代,更新最短距离
if (!f[j] &&(dis[k]+a[k][j]<dis[j]))dis[j]=dis[k]+a[k][j];
}
思想正确,不保证粘贴正确
但是dijsktra不能有负权。因为有负权的话它就会不停的做松弛就像刷副本刷钱一样。
Bellman-ford
判断是否有负权
和dijsktra差不多不过加了一个松弛次数判断,如果进行了n次松弛,还可以再进行松弛,就说明有负权,因为遍历所有的边,只需要n次。具体代码我也懒的敲了
spfa
Bellman-ford每次都要检查所有那边,但是如果上一次,x点到s的最短距离没有改变,那么这一次的检查就是多余的。所以我们只要检查刚被松弛过了的点就可以了。代码如下:
用队列记录松弛过的地方。SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身会再次被改进,于是再次用来改进其它的点,这样反复迭代下去。