HDOJ3790 最短路徑問題 --- SPFA演算法求多關鍵字最短路
阿新 • • 發佈:2018-12-18
Problem Description
給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。
Input
輸入n,m,點的編號是1~n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度為d,花費為p。最後一行是兩個數 s,t;起點s,終點。n和m為0時輸入結束。 (1<n<=1000, 0<m<100000, s != t)
Output
輸出 一行有兩個數, 最短距離及其花費。
Sample Input
3 2 1 2 5 6 2 3 4 5 1 3 0 0
Sample Output
9 11
題解:
SPFA演算法是西南交通大學計算機學院段凡丁院長提出,相當於是Bellman-ford演算法的優化。
在SPFA中,先將起點入佇列,一個while迴圈取出隊首元素,找出與其鄰接的節點,判斷是否能夠鬆弛,如果可以鬆弛,就更新最短路,並將其入隊。最終可以計算出單源最短路徑(如果一個節點入隊超過N次,則說明不存在最短路,即有負權迴路,N為節點個數)。
SPFA通常採用鄰接表,此題有2個關鍵字:路徑長度和花費。 只需要在判斷鬆弛條件的時候改變下就行,如果鬆弛後的長度和不鬆弛相等,就判斷兩種情況下的花費,如果鬆弛後的花費可以更小,則鬆弛節點。
另外需要額外一個數組記錄下所有節點當前最小花費。
#include <cstdio> #include <algorithm> #include <vector> #include <cstring> #include <queue> #define INF 0x3fffffff using namespace std; int n,m; int s,t; struct Node { int to,weight,cost; void set(int a,int b,int c) { to = a,weight = b,cost = c; } }node[200010]; struct Point { int dis,cost; }point[1010]; int cur; vector<Node> vec[1010]; queue<int> q; // SPFA最短路徑 void SPFA() { q.push(s); int temp; int cnt; while(!q.empty()) { temp = q.front(); q.pop(); // 遍歷周圍的點 cnt = vec[temp].size(); for(int i = 0;i < cnt;i++) { int to = vec[temp][i].to; int weight = vec[temp][i].weight; int cost = vec[temp][i].cost; // 判斷是否需要鬆弛 if(point[to].dis > point[temp].dis + weight) { point[to].dis = point[temp].dis + weight; point[to].cost = point[temp].cost + cost; q.push(to); } else if((point[to].dis == point[temp].dis + weight) && (point[to].cost > point[temp].cost + cost) ) { point[to].cost = point[temp].cost + cost; q.push(to); } } } printf("%d %d\n",point[t].dis,point[t].cost); } int main() { while(scanf("%d%d",&n,&m) != EOF) { if(n == 0 && m == 0) break; memset(vec,0,sizeof(vec)); while(!q.empty()) q.pop(); cur = 0; //vec.clear(); for(int i = 1;i <= n;i++) { point[i].dis = INF; point[i].cost = INF; } int a,b,c,d; for(int i = 0;i < m;i++) { scanf("%d%d%d%d",&a,&b,&c,&d); node[cur].set(b,c,d); vec[a].push_back(node[cur]); cur++; node[cur].set(a,c,d); vec[b].push_back(node[cur]); cur++; } scanf("%d%d",&s,&t); point[s].dis = 0; point[s].cost = 0; SPFA(); } return 0; }