一遍学会最短路算法!

最短路问题

最短路问题:在一个图中找到 起点到终点 距离最短的问题。

定义f(i,j)为点 i 到点 j之间的距离

一.Floyd算法–求多源最短路问题—可以处理负权边----时间复杂度O(n^3)

算法思想:f(i,j) = min( f(i,j) , f(i,K) + f(k,j) )

算法代码:

for(int i=1;i<=n;i++)	//枚举中间边
	for(int j=1;j<=n;j++)	//枚举起点
		for(int k=1;k<=n;k++)	//枚举终点
			if(e[j][k]>e[j][i] + e[i][k])e[j][k] = e[j][i] + e[i][k];

二.Dijkstra算法–求单源最短路问题–不能处理负权边—时间复杂度O(mlogm)

算法思想:用距离起点最近的边 去更新其他的边------------边只会被 比它短的一条边更新

算法代码:

void dijkstra(int start)
{
    memset(dist,0x3f,sizeof dist);
    dist[start] = 0;
    for(int i=1;i<=n;i++)
    {
        //第一步找到距离当前点的最短的边(没有被确定为最短的)
        int t = 0;
        for(int i=1;i<=n;i++)
            if(!st[i]&&dist[i]<dist[t])t = i;
        
        st[t] = true;//已经被确定为最短了 不会被后面的边更新 因为后面的边都比它要大
        
        for(int i=1;i<=n;i++)//更新其他节点
            dist[i] = min(dist[i],dist[t]+e[t][i]);
	}
}

寻找最短边的过程可以被优先队列优化

void dijkstra(int start)
{
    memset(dis,0x3f,sizeof dis);
    dis[be] = 0;
    priority_queue<PII,vector<PII>,greater<PII>> que;
    que.push({0,be});
    
    while(que.size())
    {
        auto no = que.top();
        que.pop();
        int ver = no.second,distan = no.first;
        if(st[ver])continue;
        st[ver] = 1;

        for(int i=h[ver];~i;i=ne[i])
        {
            int j = e[i];
            if(dis[j]>distan+c[i])
            {
                dis[j] = distan + c[i];
                que.push({dis[j],j});
            }
        }
    }
    if(dis[n]!=0x3f3f3f3f)return dis[n];
    else return -1;
}

三.bellman-ford算法—可以处理负权边—时间复杂度O(M) 最坏O(NM) M:边的数量

算法原理:用每一条边对dist[]数组经行松弛-----去掉起点的flody算法

朴素版代码:

for(int k=1;k<=n;k++)
	for(int i=1;i<=m;i++)
		if(dist[end[i]]>dist[start[i]]+w[i])dist[end[i]] = dist[start[i]] + w[i];

//相当于
for(int i=1;i<=n;i++)
    for(int k=1;k<=n;k++)
    	if(e[1][i]>e[1][k]+e[k][i])e[1][i] = e[1][k] + e[k][i];

队列优化—也称spfa算法:

在松弛的过程中 有一些点可能没经过n-1轮就找到了它的最短路。所以我们只用将每次被松弛的点放入队列中就好(如果它这一轮没被松弛,那么它的缩短距离的效果就已经没用了)

算法代码:

int spfa()
{
    memset(dist,0x3f,sizeof dist);
    dist[0] = 0;
    st[0] = true;
    queue<int> q;
    q.push(0);
    while(q.size())
    {
        int x = q.front();
        q.pop();
        st[x] = false;
        for(int i=h[x];~i;i=ne[i])
        {
            int j = e[i],w = c[i];
            if(dist[j]>dist[x]+w)
            {
                dist[j] = dist[x] + w;
                if(!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值