一,求多源最短路(即任意两点间的最短路)
Floyd: 时间复杂度为O(n^3),Floyd还可以用于计算传递闭包和无向图最小环,是一个值得记住的算法。
void floyd()
{
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]);
}
二,求给定起点到任意点的最短路
1.SPFA
SPFA一般只用于费用流和判断负环,没有负环尽量不使用SPFA**,时间复杂度为O(km), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2(不存在环的情况下),m为边的数量。
其中判断负环的又分为几种情况:
(1)从起点到终点的路上有负环,最短路为负无穷。
(2)从起点可以到负环,但是一旦进入负环便无法到达终点,所以最短路存在。
(3)存在负环,但是从起点无法到达。
void spfa(int s)//s为起点
{
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[s] = 0;
queue<int> q;
q.push(s);
while (q.size())
{
int x = q.front();
q.pop();
v[x] = 0;
for (int i = head[x]; i; i = nex[i])
{
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z)
{
d[y] = d[x] + z;
if (!v[y])
{
q.push(y);
v[y] = 1;
}
}
}
}
}
利用SPFA算法判断有没有环(正环和负环都行):
void spfa(int s)//s为起点
{
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[s] = 0;
queue<int> q;
q.push(s);
while (q.size())
{
int x = q.front();
q.pop();
v[x] = 0;
for (int i = head[x]; i; i = nex[i])
{
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z)
{
d[y] = d[x] + z;
cnt[y] = cnt[x] + 1;//cnt[y]表示起点到y的最短路径包含的边数
if (cnt[y] >= n)//n为点数
{
puts("存在负环");
return;
}
if (!v[y])
{
q.push(y);
v[y] = 1;
}
}
}
}
}
spfa算法的SLF优化:
void spfa(int s)//s为起点
{
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[s] = 0;
deque<int> q;
q.push_front(s);
while (q.size())
{
int x = q.front();
q.pop_front();
v[x] = 0;
for (int i = head[x]; i; i = nex[i])
{
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z)
{
d[y] = d[x] + z;
if (!v[y])
{
if (q.size() && d[y] < d[q.front()])
q.push_front(y);
else
q.push_back(y);
v[y] = 1;
}
}
}
}
}
2.迪杰斯特拉算法(Dijkstra)
基于贪心的思想,不能处理负权的情况,每个点额外维护一个属性,表示是否确定了最短路。 时间复杂度为O( (m + n) log(n) ),迪杰斯特拉算法不能判断环的存在。
void dij(int s)//s为起点
{
//
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[s] = 0;
priority_queue< pair<int, int> > q;//pair第一维为d的相反数,第二维为节点编号
q.push(make_pair(0, s));
while (q.size())
{
int x = q.top().second;//每次取d最小的编号
q.pop();
if (v[x])
continue;
v[x] = 1;
for (int i = head[x]; i; i = nex[i])
{
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z)
{
d[y] = d[x] + z;
q.push(make_pair(-d[y], y));
}
}
}
}
三:
其他变形
可能需要求解
最长路。把所有边权取相反数即可
乘积最大。边权相乘,可以通过取对数转化为加法。
二分查找答案。
反向建边。