【洛谷P3371】【模板】單源最短路徑【FLOYED Spfa 最短路】

題目描述:

如題,給出一個有向圖,請輸出從某一點出發到所有點的最短路徑長度。

輸入格式:

第一行包含三個整數 n,m,s分別表示點的個數、有向邊的個數、出發點的編號。

接下來 m 行每行包含三個整數 u,v,w表示一條 u →v 的,長度爲 w 的邊。

輸出格式:

輸出一行 n 個整數,第 i 個表示 s 到第 i 個點的最短路徑,若不能到達則輸出 2^31-1。

輸入輸出樣例:

輸入:

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

輸出:

0 2 4 3

分析&說明:

學習了基礎的鬆弛操作後,我們來學習最樸素的Floyd算法:

#include<iostream>
#include<cstdio>
using namespace std;
long long  a[7005][7005],s,n,m,u,v,d;
const int inf=0x7fffffff;
int main()
{
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            a[i][j]=inf;
            //把鄰接矩陣數組重置爲inf
        }
    }
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v>>d;
        a[u][v]=min(a[u][v],d);
        //鄰接矩陣存儲
    }
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            if(i==k||a[i][k]==inf)
            {
                continue;
            }
            for(int j=1;j<=n;j++)
            {
                a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
            }//鬆弛操作
        }
     }
    a[s][s]=0; //起點標記爲0
    for(int i=1;i<=n;i++)
    {
        printf("%d ",a[s][i]);
        //輸出
    }
    return 0;
}

然而我鍾愛的Floyed洛谷上只有40分
所以只能用Spfa了!

Spfa代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,s;
struct node
{
    int to,next,w;
}a[510000];//鄰接鏈表存圖,來節省空間 
int head[500100],vis[510000],dis[510000],st[510000];
int tot=0;
void init()
{
    memset(dis,0x3f,sizeof(dis));
    for(int i=1;i<=m;i++)
    {
        head[i]=-1;
    }
}
void add(int u,int v,int w)
{
    a[++tot].to=v;
    a[tot].w=w;
    a[tot].next=head[u];
    head[u]=tot;
}
void spfa()
{
    int u,l=0;
    int r=1;
    st[1]=s;
    vis[s]=1;
    dis[s]=0;//上面幾步爲SPFA的初始化 
    while(l<r)
    {
        u=st[++l];//隊列的第一個元素出列,然後找該元素相連的其它點 
        vis[u]=0;//出列操作 
        for(int i=head[u];i!=-1;i=a[i].next)
        {
            if(dis[a[i].to]>dis[u]+a[i].w)//如果新的邊比原先的短,那就更新權值 
            {
                dis[a[i].to]=dis[u]+a[i].w;
                if(vis[a[i].to]==0)//如果被更新的點原先不在隊列裏,就把它加進來,這樣做的好處是避免了每一個點的重複詢問,降低了時間複雜度 
                {
                    vis[a[i].to]=1;
                    st[++r]=a[i].to;//被更新的點加入隊列 
                }
            }
        }
    }
}
int main()
{
    int u,v,w;
    cin>>n>>m>>s;
    init();
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v>>w;
        add(u,v,w);
    }
    spfa();//SPFA主體 
    for(int i=1;i<=n;i++)
    {
        if(i==s) cout<<0<<" ";
        else
        {
            if(dis[i]==0x3f3f3f3f) cout<<2147483647<<" ";//如果沒有被連,那就輸出2147483647 
            else cout<<dis[i]<<" ";
        }    
    }
return 0;
}
/*
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章