1. 程式人生 > >單源最短路徑(最短路)

單源最短路徑(最短路)

ext getchar 路徑 鄰接鏈表 單源最短路 fin struct true com

洛谷——P3371 【模板】單源最短路徑(spfa)

題目描述

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

輸入輸出格式

輸入格式:

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

接下來M行每行包含三個整數Fi、Gi、Wi,分別表示第i條有向邊的出發點、目標點和長度。

輸出格式:

一行,包含N個用空格分隔的整數,其中第i個整數表示從點S出發到點i的最短路徑長度(若S=i則最短路徑長度為0,若從點S無法到達點i,則最短路徑長度為2147483647)

輸入輸出樣例

輸入樣例#1:
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
輸出樣例#1:
0 2 4 3

說明

時空限制:1000ms,128M

數據規模:

對於20%的數據:N<=5,M<=15

對於40%的數據:N<=100,M<=10000

對於70%的數據:N<=1000,M<=100000

對於100%的數據:N<=10000,M<=500000

樣例說明:

技術分享

代碼:

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include
<iostream> #include<algorithm> #define N 10001 #define maxn 2147483647LL using namespace std; queue<int>q; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-) f=-1; ch=getchar(); } while(ch>=
0&&ch<=9) { x=x*10+ch-0; ch=getchar(); } return x*f; } struct Edge { int to,ds,next; }edge[500005]; int n,m,s,tot,x,y,z,dis[N],head[N];//n 點的個數 m 連邊的條數 s 起點 dis 儲存最小邊 bool vis[N];//標記一個點是否在隊列中 void add(int from,int to,int dis) { tot++; edge[tot].to=to; edge[tot].ds=dis; edge[tot].next=head[from]; head[from]=tot; }//鄰接鏈表存邊 void spfa(int s) { for(int i=1;i<=n;i++) vis[i]=false,dis[i]=maxn;//初始化 dis[s]=0,vis[s]=true;//加入第一個點(起點) q.push(s);//將起點入隊 while(!q.empty())//如果隊列不為空,就接著執行操作,直到隊列為空 { int x=q.front();//從隊列的頭元素開始進行更新最短路 q.pop(); //將隊列頭元素彈出 for(int i=head[x];i;i=edge[i].next)//枚舉與該點連接的邊 i=head[x]當前所要更新的點在隊列中的位置 i=edge[i].next與當前點相連的點 { if(dis[x]+edge[i].ds<dis[edge[i].to])//如果能更新最小值 { dis[edge[i].to]=dis[x]+edge[i].ds;//更新最小值 if(!vis[edge[i].to])//將所能更新的沒入隊的元素入隊 { vis[edge[i].to]=true;//標記為已入隊 q.push(edge[i].to);//推入隊中 } } } vis[x]=false;//將該點標記為出隊列 } } int main() { n=read(),m=read(),s=read(); for(int i=1;i<=m;i++) { x=read(),y=read(),z=read(); add(x,y,z);//用鄰接鏈表儲存 } spfa(s); for(int i=1;i<=n;i++) printf("%d ",dis[i]); return 0; }

單源最短路徑(最短路)