bellman-ford
算法的核心是“松弛”操作,即一趟利用所有边对所到的点进行更新,当更新完n-1趟后,如果不存在负环则终点的距离可以确定,否则会一直更新。
因此复杂度是O(nm)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 10010 , INF = 0x3f3f3f3f;
struct Edge{
int a , b , c;
}edges[N];
int dist[N];
int last[N];
int n , m , k;
void bellman_ford()
{
memset(dist , 0x3f , sizeof dist);
dist[1] = 0;
for(int i = 0 ; i < k ; i++)
{
memcpy(last , dist , sizeof dist);
for(int j = 0 ; j < m ; j++)
{
auto e = edges[j];
dist[e.b] = min(dist[e.b] , last[e.a] + e.c);
}
}
}
int main()
{
cin >> n >> m >> k;
for(int i = 0 ; i < m ; i++)
{
int a , b , c;
cin >> a >> b >> c;
edges[i] = {a , b , c};
}
bellman_ford();
if(dist[n] > INF / 2) puts("impossible");
else cout << dist[n] << endl;
return 0;
}
spfa
对bellman-ford算法的一个优化,bellman-ford每一趟都对所有边进行松弛,但其实是没必要的,因为有的点在上一次松弛后到起点的距离并没有改变,因此也不无法去更新它的点。在spfa中就用一个队列来存储已经被更新过的点。
一般来说时间复杂度是O(m),但最坏是O(nm)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100010;
int e[N] , ne[N] , w[N] , h[N] , idx;
bool st[N];
int dist[N];
int n , m;
void add(int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx++;
}
void spfa()
{
queue<int> q;
memset(dist , 0x3f, sizeof dist);
dist[1] = 0;
q.push(1);
while(q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t] ; ~i ; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if(!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
}
int main()
{
cin >> n >> m;
memset(h , -1 , sizeof h);
while(m--)
{
int a , b , c;
cin >> a >> b >> c;
add(a , b , c);
}
spfa();
if(dist[n] == 0x3f3f3f3f) puts("impossible");
else cout << dist[n] << endl;
return 0;
}