Dijkstra:(只能处理非负的)
贪心思想:
1、找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离。
2、此后不需要再关心1中的“最短距离已确定的顶点”。
优先队列优化:
在队列中取出d值最小的结点x,然后从x出发更新所有的边的d值。
初始化:
first[u] 结点u的第一条边
next[i] 边i的下一条边
d -> INF
时间复杂度O(elogv)
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
//距离,边序号
typedef pair<int ,int> P;
priority_queue<P, vector<P>, greater<P> >que;
const int MAX_N = 10000, MAX_M = 10000;
int d[MAX_N];
struct E
{
int u, v, w;
}e[MAX_M];
int first[MAX_N], next[MAX_M];
void Dijkstra(int s)
{
//初始化,距离数组d,队列
memset(d, 0x3f, sizeof(d));
d[s] = 0;
que.push(P(d[s], s));
while(que.size())
{
P x = que.top(); que.pop(); //取出
int u = x.second;
if(x.first != d[u]) //已经算过了,跳过
continue;
for(int i = first[u]; i != -1; i = next[i])
if(d[u] + e[i].w < d[e[i].v])
{
d[e[i].v] = d[u] + e[i].w;
que.push(P(d[e[i].v], e[i].v));
}
}
}
int main(int argc, char *argv[])
{
memset(first, -1, sizeof(first));
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
next[i] = first[e[i].u];
first[e[i].u] = i;
}
Dijkstra(e[0].u);
printf("%d\n", d[5]);
return 0;
}
SPFA算法 负环最短路(用队列优化对Bellman Ford算法的优化):
时间复杂度:O(ke)。
初始化:
first[u] 结点u的第一条边
next[i] 边i的下一条边
d -> INF
bool inq[MAX_N];
void SPFA(int s)
{
//初始化距离d,队列,inq队列标志
queue<int> que;
memset(d, 0x3f, sizeof(d));
d[s] = 0;
memset(inq, 0, sizeof(inq));
que.push(s);
while(que.size())
{
int u = que.front(); que.pop();
//清除标志
inq[u] = false;
//对每一条邻边松弛操作
for(int i = first[u]; i != -1; i = next[i])
if(d[e[i].u] + e[i].w < d[e[i].v])
{
d[e[i].v] = d[e[i].u] + e[i].w;
if(!inq[e[i].v])
{
inq[e[i].v] = true;
que.push(e[i].v);
}
}
}
}
Bellman Ford算法判断是否存在负环:
若循环执行了n-1次,则存在负环。
注:d初始化为0即可
bool find_negative_loop()
{
memset(d, 0, sizeof(d));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
int u = e[j].u, v = e[j].v, w = e[j].w;
if(d[u] + w < d[v])
{
d[v] = d[u] + w;
if(i == n-1)
return true;
}
}
return false;
}
Floyd-Warshall任意两点最短路算法:
动态规划的思想:
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
时间复杂度O(v^3)。
初始化:
d[][] -> INF
d[i][i] = 0;
d[u][v] = w;
void Floyd()
{
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
测试:
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
int n, m;
//dist, u
typedef pair<int, int> P;
priority_queue<P, vector<P>, greater<P> >que;
const int MAX_N = 10000, MAX_M = 10000;
int d[MAX_N]; //distant
struct E
{
int u, v, w;
}e[MAX_M];
int first[MAX_N], nexte[MAX_M];
void Dijkstra(int s)
{
memset(d, 0x3f, sizeof(d));
d[s] = 0;
que.push(P(d[s], s));
while(que.size())
{
P x = que.top(); que.pop();
int u = x.second; //u
if(x.first != d[u]) //calc~ed
continue;
for(int i = first[u]; i != -1; i = nexte[i])
if(d[u] + e[i].w < d[e[i].v])
{
d[e[i].v] = d[u] + e[i].w;
que.push(P(d[e[i].v], e[i].v));
}
}
}
bool inq[MAX_N];
void SPFA(int s)
{
//init
queue<int> que;
memset(d, 0x3f, sizeof(d));
d[s] = 0;
memset(inq, 0, sizeof(inq));
que.push(s);
while(que.size())
{
int u = que.front(); que.pop();
//clear flag
inq[u] = false;
//relax
for(int i = first[u]; i != -1; i = nexte[i])
if(d[e[i].u] + e[i].w < d[e[i].v])
{
d[e[i].v] = d[e[i].u] + e[i].w;
if(!inq[e[i].v])
{
inq[e[i].v] = true;
que.push(e[i].v);
}
}
}
}
int dist[MAX_N][MAX_N];
void Floyd()
{
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
int main()
{
freopen("in.txt", "r", stdin);
memset(first, -1, sizeof(first));
//Floyd
memset(dist, 0x3f, sizeof(dist));
for(int i = 0; i < n; i++) dist[i][i] = 0;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
nexte[i] = first[e[i].u];
first[e[i].u] = i;
//Floyd
dist[e[i].u][e[i].v] = e[i].w;
}
Dijkstra(e[0].u);
printf("%d to %d dist = %d\n", e[0].u, n-1, d[n-1]);
SPFA(e[0].u);
printf("%d to %d dist = %d\n", e[0].u, n-1, d[n-1]);
Floyd();
printf("%d to %d dist = %d\n", e[0].u, n-1, dist[e[0].u][n-1]);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
if(dist[i][j] == 0x3f3f3f3f)
printf("INF");
else
printf("%3d", dist[i][j]);
printf(j == n-1 ? "\n" : " ");
}
return 0;
}
/************************************************************************/
/*
input:
6 8
0 2 10
0 4 30
0 5 100
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60 */
/************************************************************************/