目录
1、单源最短路问题
单源最短路问题,也可以变为一个多源最短路,只需要加一个虚拟原点指向所有的边就行。
也可以解决一个点到其它所有点的最短距离。
1.1、没有负权值
1.1.1、Dijkstra算法
时间复杂度:o(n*n*m)
int g[N][N];
int dist[N];
bool st[N];
int djs()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n - 1; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
for (int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
st[t] = true;
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
1.1.2、堆优化的Dijkstra算法
时间复杂度:o(m*logn) m为边数n为顶点数。
#define x first
#define y second
typedef pair<int, int> pii;
bool st[N] = {false};
int djs()
{
priority_queue<pii>, vector<pii>, greater<pii>> yi;
yi.push({0, 1});
while(yi.size())
{
pii t = yi.top();
yi.pop();
if(st[t.y]) continue;
st[t.y] = 1;
if(t.y == n)
{
return t.x;
}
for(int i = h[t.y]; i != -1; i = ne[i])
{
if(st[e[i]]) continue;
yi.push({t.x + w[i], e[i]});
}
}
}
1.2有负权值
1.2.1、Bellman-Ford算法
时间复杂度:o(n*m) 分别为边数和顶点数。
该算法也可以在限制最多走的边数情况下的最短路。
int n, m; // n表示点数,m表示边数
int dist[N]; // dist[x]存储1到x的最短路距离
struct Edge // 边,a表示出点,b表示入点,w表示边的权重
{
int a, b, w;
}edges[M];
// 求1到n的最短路距离,如果无法从1走到n,则返回-1。
int bellman_ford()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
// 如果第n次迭代仍然会松弛三角不等式,就说明存在一条长度是n+1的最短路径,由抽屉原理,路径中至少存在两个相同的点,说明图中存在负权回路。
for (int i = 0; i < n; i ++ )
{
for (int j = 0; j < m; j ++ )
{
int a = edges[j].a, b = edges[j].b, w = edges[j].w;
if (dist[b] > dist[a] + w)
dist[b] = dist[a] + w;
}
}
if (dist[n] > 0x3f3f3f3f / 2) return -1;
return dist[n];
}
// yxc模板
1.2.2、SPFA算法
时间复杂度为o(n)~o(nlogn)
#define x first
#define y second
typedef pair<int, int> pii;
const int N = 1e5+ 10;
int n, m, dist[N];
vector<pii> o[N]; // first 为指向的顶点,second 为权值
bool st[N];
void spfa(int a) // 该板子是用vector建的图,时间肯定没有邻接表快。直需要改一下建图方式即可。
{
queue<int> yi;
yi.push(1);
st[1] = 1;
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
while(yi.size())
{
int x = yi.front();
yi.pop();
st[x] = 0;
for(auto i : o[x])
{
int j = i.x;
if(dist[j] > dist[x] + i.y)
{
dist[j] = dist[x] + i.y;
if(!st[j])
{
yi.push(j);
st[j] = 1;
}
}
}
}
}
2、多源汇最短路问题
Floryd算法
时间复杂度:o(n^3)
void floyd() // 求得任意两点之间的最短距离
{
for (int i = 1; i <= n; i ++ ) // 初始化
for (int j = 1; j <= n; j ++ )
if (i == j) d[i][j] = 0;
else d[i][j] = INF;
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}