单源最短距离:固定一个起点,计算它到其他点的最短距离的问题。
1.Bellman-Ford算法
记录从源点s出发到点i的最短距离为d[i],利用d[i]=min{d[j]+edge(j,i), d[i]}不断更新数组d
一开始设置距离源点s的距离d[s]=0,到其他点的距离d[i]=INF,利用上面的递推式更新数组,只要图中没有负圈,更新的次数就是有限次的
#define INF 1<<28
static const int MAX = 10050;
struct edge{
int from, to, cost;
};
edge es[MAX]; //边
int d[MAX]; //距源点的最短距离
int V; //顶点数
int E; //边数
//Bellman-Ford
void shortest_path(int s)
{
for (int i = 0; i < V; i++)
d[i] = INF;
d[s] = 0;
while (1)
{
bool update = false; //更新标记
//更新距离
for (int i = 0; i < MAX; i++)
{
edge e = es[i];
if (d[e.from] != INF && d[e.to] > d[e.from] + e.cost)
{
update = true;
d[e.to] = d[e.from] + e.cost;
}
}
if (!update)
break;
}
}
2.Dijkstra算法
利用Bellman-Ford算法,即使d[i]不是最短距离也有可能更新,即使d[i]没有变化,也会从头出发检查所有的边。所以对算法做了以下修改:
(1)找到最短距离确定的点,更新与它相邻的顶点
(2)对于在(1)确定的点,下次不再检查
#define INF 1<<28
static const int MAX = 10050;
struct edge{
int from, to, cost;
};
edge es[MAX]; //边
int cost[MAX][MAX]; //cost[i][j]表示从i到j的权值,如果不存在则为INF
int d[MAX]; //距源点的最短距离
bool used[MAX]; //记录该点是否使用过
int V; //顶点数
int E; //边数
void dijkstra(int s)
{
for (int i = 0; i < V; i++)
{
used[i] = false;
d[i] = INF;
}
d[s] = 0;
while (1)
{
int v = -1;
for (int i = 0; i < V; i++)
if (!used[i] && ((v == -1) || d[v] > d[i]))
v = i;
if (v == -1)
break;
used[v] = true;
for (int i = 0; i < V; i++)
d[i] = min(d[i], d[v] + cost[v][i]);
}
}