图论$\cdot$最短路问题

时间:2023-03-08 23:29:09
图论$\cdot$最短路问题
  • Dijkstra单源最短路径算法

Dijkstra可以计算出发点到每个点的最短路,及单源最短路径(SSSP)。这一特点使得Dijkstra常常用来进行其他算法的预处理。用Dijkstra算法计算最短路的代码如下:

注:代码注释参见《算法竞赛入门经典——训练指南》(刘汝佳)

 struct Dijkstra{
int n, m;
vector<E> e;
vector<int> G[maxn];
bool done[maxn];
int d[maxn];
int p[maxn];
void init(int n){
this->n = n;
FOR(i, , n - ) G[i].clear();
e.clear();
}
void addE(int from, int to, int dist){
e.pb(E(from, to, dist));
m = e.size();
G[from].pb(m - );
}
void dijkstra(int s){
priority_queue<HeapNode> Q;
FOR(i, , n - ) d[i] = int_inf;
d[s] = ;
clr(done, );
Q.push(HeapNode(, s));
while(!Q.empty()){
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if(done[u]) continue;
done[u] = ;
int sz = G[u].size();
FOR(i, , sz - ){
E &y = e[G[u][i]];
if(d[y.to] > d[u] + y.dist){
d[y.to] = d[u] + y.dist;
p[y.to] = G[u][i];
Q.push(HeapNode(d[y.to], y.to));
}
}
}
}
};
  • Bellman-Ford算法

Bellman-Ford算法的一个重要应用是判负圈。在迭代$n-1$次后如果还可以进行松弛(relax)操作,说明一定存在负圈。如果采用队列实现,那么当某个结点入队了$n$次时可以判断出存在负圈,代码如下:

 struct Bellman_Ford{
int n, m;
vector<E> e;
vector<int> G[maxn];
bool inq[maxn];
int d[maxn];
int p[maxn];
int cnt[maxn];
void init(int n){
this->n = n;
FOR(i, , n - ) G[i].clear();
e.clear();
}
void addE(int from, int to, int dist){
e.pb(E(from, to, dist));
m = e.size();
G[from].pb(m - );
}
bool negCyc(){
queue<int> Q;
clr(inq, ), clr(cnt, );
FOR(i, , n - ) d[i] = , inq[i] = , Q.push(i);
while(!Q.empty()){
int u = Q.front(); Q.pop();
inq[u] = ;
int sz = G[u].size();
FOR(i, , sz - ){
E &y = e[G[u][i]];
if(d[y.to] > d[u] + y.dist){
d[y].to = d[u] + y.dist;
p[e.to] = G[u][i];
if(!inq[y.to]){
Q.push(y.to);
inq[y.to] = ;
if(++cnt[y.to] > n) return ;
}
}
}
}
return ;
}
};