*47. 参加科学大会(第六期模拟笔试)-Dijkstra(堆优化版)
这个版本的Dijkstra强度很大,很大一部分原因是对优先队列不熟悉。
优先队列的定义:
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pq;
其中,
- pair<int, int>是指定优先队列的存储数据类型;
- vector<pair<int, int>>是指定优先队列的底层容器类型;
- mycomparison是用于定义优先队列排序规则的比较函数。
时间复杂度:
O
(
E
l
o
g
E
)
O(ElogE)
O(ElogE)
空间复杂度:
O
(
V
+
E
)
O(V + E)
O(V+E)
// c++
#include<bits/stdc++.h>
using namespace std;
class mycmp{
public:
bool operator()(const pair<int, int> & left, const pair<int, int> & right){
return left.second > right.second;
}
};
bool cmp(const pair<int, int> & left, const pair<int, int> & right){
return left.second > right.second;
}
struct Edge{
int to;
int val;
Edge(int t, int v): to(t), val(v){}
};
int main(){
int n, m;
cin>>n>>m;
vector<list<Edge>> edges(n+1);
int left, right, val;
for(int i=0; i<m; i++){
cin>>left>>right>>val;
edges[left].push_back(Edge(right, val));
}
int start = 1;
int end = n;
vector<int> minDist(n+1, INT_MAX);
vector<bool> visited(n+1, false);
//
priority_queue<pair<int, int>, vector<pair<int, int>>, mycmp> pq;
//
pq.push({start, 0});
minDist[start] = 0;
while(!pq.empty()){
pair<int, int> cur = pq.top();
pq.pop();
if(visited[cur.first]) continue;
// 标记访问
visited[cur.first] = true;
// 更新节点到源点距离
for(Edge edge : edges[cur.first]){
if(!visited[edge.to] && edge.val + minDist[cur.first] < minDist[edge.to]){
minDist[edge.to] = edge.val + minDist[cur.first];
pq.push({edge.to, minDist[edge.to]});
}
}
}
if(minDist[end]!=INT_MAX) cout<<minDist[end];
else cout<<-1;
return 0;
}
*94. 城市间货物运输 I-Bellman_ford 算法
时间复杂度:
O
(
V
∗
E
)
O(V * E)
O(V∗E)
空间复杂度:
O
(
V
)
O(V)
O(V)
// c++
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,left,right,val;
cin>>n>>m;
vector<vector<int>> edges;
for(int i=0; i<m; i++){
cin>>left>>right>>val;
edges.push_back({left, right, val});
}
int start = 1;
int end = n;
vector<int> minDist(n+1, INT_MAX);
minDist[start] = 0;
// 对所有边松弛n-1次
for(int i=1; i<n; i++){
for(vector<int> &edge : edges){
int from = edge[0];
int to = edge[1];
int val = edge[2];
// 松弛操作
if(minDist[from] != INT_MAX && minDist[to] > minDist[from]+val){
minDist[to] = minDist[from]+val;
}
}
}
if(minDist[end] == INT_MAX) cout<<"unconnected";
else cout<<minDist[end];
return 0;
}
总结
Dijkstra算法每次只更新与当前节点相连的结点的最小路径长度,BF算法每次更新所有结点的最小路径长度。
BF算法第k次计算的是距离源点有k条边的结点的最小路径长度。
Dijkstra只适用于无负权值的图,BF算法适用于有负权值无负回路的图。
BF在负回路图中会陷入死循环。若中间某次遍历各点的最短路径不再更新则遍历结束。
BF算法可用于检测是否有负回路:若n-1次遍历都结束后,若再进行一次遍历还能得到某些结点的更短路径,则存在负环路。