写于 CSP 前一天,复习最短路。
每次全图进行松弛,可以证明执行 n n n 次后可以找到最短路。时间复杂度 O ( n m ) O(nm) O(nm)。
// bellman-ford
#include
#define int long long
using namespace std;
const int N = 1e5 + 5;
struct Edge{
int to, w;
};
vector <Edge> G[N];
int n, m, s, dis[N];
signed main()
{
cin >> n >> m >> s;
for(int i=1; i<=n; i++)
dis[i] = INT_MAX;
// s 为起点
dis[s] = 0;
for(int i=1; i<=m; i++)
{
int u, v, w;
cin >> u >> v >> w;
G[u].push_back({v, w});
}
for(int i=1; i<=n; i++)
{
for(int u=1; u<=n; u++)
for(Edge i : G[u])
{
int v = i.to, w = i.w;
if(dis[v] > dis[u] + w)
dis[v] = dis[u] + w;
}
}
for(int i=1; i<=n; i++)
cout << dis[i] << " ";
}
bellman-ford 每次对全图松弛有些多余,显然对于每一轮,只有上一轮进行松弛的点在本轮才能进行松弛。用队列存需要松弛的点。
// spfa
#include
#define int long long
using namespace std;
const int N = 1e5 + 5;
struct Edge{
int to, w;
};
vector <Edge> G[N];
int n, m, s, dis[N];
bool flag[N];
signed main()
{
cin >> n >> m >> s;
for(int i=1; i<=n; i++)
dis[i] = INT_MAX;
dis[s] = 0;
for(int i=1; i<=m; i++)
{
int u, v, w;
cin >> u >> v >> w;
G[u].push_back({v, w});
}
queue <int> q; q.push(s);
while(!q.empty())
{
int u = q.front(); q.pop();
if(flag[u]) continue;
flag[u] = 1;
for(Edge i : G[u])
{
int v = i.to, w = i.w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push(v);
}
}
flag[u] = 0;
}
for(int i=1; i<=n; i++)
cout << dis[i] << " ";
}
要求:边权非负。
过程:两个集合 S , T S, T S,T 分别表示已确定最短路及未确定最短路的点集,初始时所有点都在 T T T 中, d i s ( s ) = 0 dis(s)=0 dis(s)=0,其余点 d i s = ∞ dis = \infin dis=∞。每次取 T T T 中 d i s dis dis 最小的点将其加入 S S S 中,对其所有出边进行松弛。
可以用堆维护 T T T 中距离最小的点。
证明: ∀ u ∈ T \forall u \in T ∀u∈T, u u u 当前的最短距离均有 S S S 中元素转移记为 D u D_u Du。对于每次取出的 T T T 中 D D D 最小的 u u u,考虑到边权非负且 D u D_u Du 最小,从 T T T 中其他点转移一定不优,故 D u D_u Du 即为最短路。
复杂度:考虑到每个点可能被多次放入堆中,堆内至多 m m m 个元素。时间复杂度 O ( n log m + m ) O(n \log m+m) O(nlogm+m)。
// dijisktra
#include
#define int long long
using namespace std;
const int N = 1e5 + 5;
struct Edge{
int to, w;
};
vector <Edge> G[N];
int n, m, s, dis[N];
bool flag[N];
struct Node{
int ver, val;
};
bool operator < (Node x, Node y)
{
return x.val > y.val;
}
signed main()
{
cin >> n >> m >> s;
for(int i=1; i<=n; i++)
dis[i] = INT_MAX;
dis[s] = 0;
for(int i=1; i<=m; i++)
{
int u, v, w;
cin >> u >> v >> w;
G[u].push_back({v, w});
}
priority_queue <Node> q;
q.push({s, 0});
while(!q.empty())
{
int u = q.top().ver; q.pop();
if(flag[u]) continue;
flag[u] = 1;
for(Edge i : G[u])
{
int v = i.to, w = i.w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({v, dis[v]});
}
}
}
for(int i=1; i<=n; i++)
cout << dis[i] << " ";
}