藍橋杯算法訓練 最短路


  算法訓練 最短路  
時間限制:1.0s   內存限制:256.0MB
       
問題描述

給定一個n個頂點,m條邊的有向圖(其中某些邊權可能為負,但保證沒有負環)。請你計算從1號點到其他點的最短路(頂點從1到n編號)。

輸入格式

第一行兩個整數n, m。

接下來的m行,每行有三個整數u, v, l,表示u到v有一條長度為l的邊。

輸出格式
共n-1行,第i行表示1號點到i+1號點的最短路。
樣例輸入
3 3
1 2 -1
2 3 -1
3 1 2
樣例輸出
-1
-2
數據規模與約定

對於10%的數據,n = 2,m = 2。

對於30%的數據,n <= 5,m <= 10。

對於100%的數據,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保證從任意頂點都能到達其他所有頂點。

         一個水題,由於有負邊,則不能使用Dijkstra算法,這里寫了一下spfa的模板,spfa算法比Dijkstra算法要快,期望的時間復雜度O(ke),其中e是邊的數目, k為所有頂點進隊的平均次數,可以證明k一般小於等於2。
       spfa算法的主要思想:dis數組標記從起點到i點的最短距離,visit數組表示是否入隊,ans數組表示每個點的入隊次數,將隊首t出隊,對t能到達的點進行松弛操作,如果能夠松弛操作,則判斷該點是否在隊列中,如果在隊列中則繼續,否則入隊,並將該點標記狀態為已入隊,該點的入隊次數加一。由於本題保證沒有負環,所以比標准的spfa算法少了一重判斷,即入隊次數如果大於n的話,表示存在負環,沒有最短路可言。另外,spfa算法不夠穩定。
       建圖:此處建圖我用的是鏈式前向星建圖,用結構體edge存邊,從名字來看,存的過程猶如鏈表一樣,使用起來就是與每個點的相連的邊是輸入順序中的第幾條邊,這樣n個點對應n條鏈表,每個鏈表要有他的頭部和尾部,尾部我們統一用-1表示,即開始時將head數組賦值為-1,頭部我們用head數組表示,當我們使用head數組的時候,打印出來的 與每個點相連的邊是按照輸入順序的倒序輸出的。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <cmath>
#include <queue>
#include <map>
#define inf 0x7f7f7f
using namespace std;
int n,m,cnt;
int head[200010],dis[200010],visit[20010];
int ans[20010];
struct node{
int to,w,next;
}edge[200010];
void add(int u,int v,int w){
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void spfa(){
queue<int>q;
for(int i = 1;i <= n;i++)
dis[i] = inf;
dis[1] = 0;
ans[1] = 1;
visit[1] = 1;
q.push(1);
while(!q.empty()){
int t = q.front();
q.pop();
visit[t] = 0;
for(int k = head[t];k!=-1;k = edge[k].next){
if(dis[edge[k].to]>dis[t]+edge[k].w){
dis[edge[k].to]=dis[t]+edge[k].w;
if(!visit[edge[k].to]){
q.push(edge[k].to);
visit[edge[k].to] = 1;
ans[edge[k].to]++;
}
}
}
}
for(int i = 2;i <= n;i++)
printf("%d\n",dis[i]);
}
int main()
{
cin>>n>>m;
int a,b,c;
memset(head,-1,sizeof(head));
for(int i = 0;i < m;i++){
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
spfa();
return 0;
}




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com