c++最短路經典問題


一提起最短路,各位oier會想到什么呢?

floyd,spfa,dij,或是bellman-ford?

其實,只要學會一種算法,大部分最短路問題就能很快解決了。

他就是堆優化的dijkstra。

首先,先講一下dij是怎么求最短路的。

Dijkstra是基於一種貪心的策略,首先用數組dis記錄起點到每個結點的最短路徑,再用一個數組保存已經找到最短路徑的點

然后,從dis數組選擇最小值,則該值就是源點s到該值對應的頂點的最短路徑,並且把該點記為已經找到最短路

此時完成一個頂點,再看這個點能否到達其它點(記為v),將dis[v]的值進行更新

不斷重復上述動作,將所有的點都更新到最短路徑

這種算法實際上是O(n^2)的時間復雜度,但我們發現在dis數組中選擇最小值時,我們可以用一些數據結構來進行優化。

其實我們可以用STL里的堆來進行優化,堆相對於線段樹以及平衡樹有着常數小,碼量小等優點,並且堆的一個妙妙的性質就是可以在nlogn的時限內滿足堆頂是堆內元素的最大(小)值,之不正是我們要的嘛?

但是呢,dij處理不了負邊,所以當題目出現負邊時,dij就不能用了。

但反過來說,只要題目沒負邊,SPFA是一定會被卡的!

下面上代碼:

#include<bits/stdc++.h>
using namespace std;
#define maxn 10005
#define maxm 500005
#define INF  1234567890
inline int read()
{
    int x=0,k=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*k;
}
struct Edge
{
    int u,v,w,next;
}e[maxm];
int head[maxn],cnt,n,m,s,vis[maxn],dis[maxn];
struct node
{
    int w,now;
    inline bool operator <(const node &x)const
    //重載運算符把最小的元素放在堆頂(大根堆)
    {
        return w>x.w;//這里注意符號要為'>'
    }
};
priority_queue<node>q;
//優先隊列,其實這里一般使用一個pair,但為了方便理解所以用的結構體
inline void add(int u,int v,int w)
{
    e[++cnt].u=u;
    //這句話對於此題不需要,但在縮點之類的問題還是有用的
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    //存儲該點的下一條邊
    head[u]=cnt;
    //更新目前該點的最后一條邊(就是這一條邊)
}
//鏈式前向星加邊
void dijkstra()
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=INF;
    }
    dis[s]=0;
    //賦初值
    q.push((node){0,s});
    while(!q.empty())
    //堆為空即為所有點都更新
    {
        node x=q.top();
        q.pop();
        int u=x.now;
        //記錄堆頂(堆內最小的邊)並將其彈出
        if(vis[u]) continue; 
        //沒有遍歷過才需要遍歷
        vis[u]=1;
        for(int i=head[u];i;i=e[i].next)
        //搜索堆頂所有連邊
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                //松弛操作
                q.push((node){dis[v],v});
                //把新遍歷到的點加入堆中
            }
        }
    }
}
int main()
{
    n=read(),m=read(),s=read();
    for(int i=1,x,y,z;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z);
    }
    dijkstra();
    for(int i=1;i<=n;i++)
    {
        printf("%d ",dis[i]);
    }
    return 0;
}

謝謝大家!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM