最后复习之最短路

这里写图片描述
有这么几种最短路算法: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[b]=min(dis[b],dis[a]+bian[j].l);
    }

四、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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值