您的位置:首页 > 其它

最后复习之最短路

2016-11-12 19:38 162 查看


有这么几种最短路算法:floyd、dijkstra、bellman-ford、spfa

一、floyd:

基本过程:枚举中间点,然后枚举起点和终点,用中间点去更新起点到终点的距离。

证明:用每个点去更新所有它能更新的点,是不是就是最短路了?(然而并不会证明)。

多源最短路、求最小环、判断负环、适合稠密图

求最小环:在求最大标号为n的最小环时,预习求出1-n-1的最短路,然后找出两个点i,j,使得i到j的距离(不会经过n,因为只求了1-n-1的最短路)加上i和j到n的距离的和最小,这就是要求的最小环。

判断负环:就是边求边判断,如果存在点到自己的距离小于0,那么就出现了负环。

模板题codevs 1557 热浪

//我的floyd只有70分,不知道floyd能不能ac这个题

for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
if (i!=k)
for (int j=1;j<=n;j++)
if (j!=k&&j!=i)
g[i][j]=min(g[i][j],g[i][k]+g[k]


二、dijkstra:

基本过程:和上一篇的prim差不多,改变就是不再是到最小生成树的距离,而是到起点的距离,即每次找离起点最近的点放入最短路。

证明:对于新加进来的肯定不会有更短的路了,虽然对这个点只有在它之前求出最短路的来更新,但是在这个点之后进来的点一定不能更新这个点到起点的距离。

单源最短路、求最小环、判断负环、适合稠密图、不能处理带有负边权的图

求最小环:不断地删去某条边,求出删去之后这条边起点到终点的最短距离,再加上这条边的长度就是目前求的环的长度,求出最小的就行了。

判断负环:临时想出来的。。如果新进来的可以更新已经求出最短路的点的距离那么就存在负环。

for (int i=1;i<=n;i++)
{
int k=0;
for (int j=1;j<=n;j++)
if (!f[j]&&dis[j]<dis[k])
k=j;
f[k]=1;
for (int j=1;j<=n;j++)
if (!f[j]&&dis[j]>dis[k]+g[k][j])
dis[j]=dis[k]+g[k][j];
}


三、bellman-ford:

基本过程:进行n-1遍对所有边的松弛操作。

证明:每次至少将一条边变成最终松弛状态(就是不会再被用来松弛了)吧,然后图中最长的最短路长度为n-1。

单源最短路、求最小环、判负环、适合稀疏图

求最小环:和dijkstra差不多去删边。

判断负环:在求完最短路之后如果还有边可以松弛,那么就存在负环。

for (int i=1;i<=n-1;i++)
for (int j=1;j<=2*m;j++)
{
a=bian[j].from;b=bian[j].to;
dis=min(dis[b],dis[a]+bian[j].l);
}


[b]四、spfa:


基本过程:通过队列,不断地松弛一些边,因为这些边的终点到起点的距离变小了,那么这些终点连接的其他点也可能可以更新,所以把这些终点们加入队列,只要队列里还有点就要继续进行,直到队列为空方才求出最短路。

证明:只要可能能更新其他点的都进队了,现在队列空了,下面的事情。。。

单源最短路、求最小环、判断负环、适合稀疏图

求最小环:应该还是删边吧,另外附上一句上面求最小环除了floyd我都没有试过(~(≧▽≦)/~啦啦啦)。

判断负环:关于spfa判断负环我只会一个比较水方法,就是如果一个点进队次数超过n次那么就存在负环,至于为什么,我并不知道。

int head=1,tail=1;
memset(dis,127/2,sizeof(dis));
dui[1]=s;f[s]=1;dis[s]=0;
int a,b,len;
while (head<=tail)
{
a=dui[head];
len=bian[a].size();//bian是vector版本的邻接表。
for (int i=0;i<len;i++)
{
b=bian[a][i].to;
if (dis[b]>dis[a]+bian[a][i].l)
{
dis[b]=dis[a]+bian[a][i].l;
if (!f[b])
{
tail++;
dui[tail]=b;
f[b]=1;
}
}

}
head++;
f[a]=0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  noip 最短路