Dijkstra算法
用途
用于解决单源最短路径问题,即在给定图和起始结点的基础上,求所有其他结点到起始结点的最短路径。
算法描述
- 创建集合S用来存放已访问结点,集合D用来存放所有结点到起始结点的最短路径;
- 从D中找到值最小的结点i(即起始结点能到达的未访问结点中路径最短的那个),将其并入S;
- 以i为新的接入点,遍历所有未访问结点,如果存在结点j到i的距离加上起始结点到i的距离小于起始结点直接到j的距离,则更新起始结点到j的最短距离D[j];
- 重复 2-3步,直到访问完所有与起始结点连通的结点。
如果要将具体的最短路径输出,只要在每次更新最短距离时保存待更新结点的前驱结点即可。
代码实现——邻接矩阵
const int maxn = 1000;
const int INF = 1000000000;
int g[maxn][maxn], n; // 邻接矩阵,结点个数
bool visit[maxn]; // 判断结点是否已访问
int d[maxn]; // 存储第i个结点到起始结点的距离
int pre[maxn]; // 记录从起点到顶点v的最短路径上v的前驱结点
void Dijkstra(int s)
{
for (int i = 0; i < n; i++) // 初始化
{
visit[i] = false;
d[i] = INF;
pre[i] = i;
}
d[s] = 0; // 到自身的距离为0
for (int i = 0; i < n; i++)
{
int u = -1, minD = INF; // 分别存放到s距离最小的结点下标和距离
for (int j = 0; j < n; j++) // 遍历所有结点,找到离s最近的结点
{
if (visit[j] == false && d[j] < minD)
{
u = j;
minD = d[j];
}
}
if (u == -1) // 不存在最近结点,即s与所有未访问结点都不连通
return;
visit[u] = true; // 找到最近结点,并标记已访问
for (int v = 0; v < n; v++) // 以u结点为新的接入点,更新未访问结点到起点的最小距离
{
// 更新距离要满足:该结点与u结点连通;未访问;以u为接入点比直接与起始结点相连更近
if (g[u][v] < INF && visit[v] == false && d[u] + g[u][v] < d[v])
{
d[v] = d[u] + g[u][v];
pre[v] = u;
}
}
}
}
代码实现——邻接表
const int maxn = 1000;
const int INF = 1000000000;
struct node
{
int v,l; // v结点编号,l边权
};
vector<node> adj[maxn]; // 邻接表
int n; // 结点个数
int d[maxn]; // 存储第i个结点到起始结点的距离
bool visit[maxn]; // 判断结点是否已访问
int pre[maxn]; // 记录从起点到顶点v的最短路径上v的前驱结点
void Dijkstra(int s)
{
for (int i = 0; i < n; i++) // 初始化
{
visit[i] = false;
d[i] = INF;
pre[i] = i;
}
d[s] = 0; // 到自身的距离为0
for (int i = 0; i < n; i++)
{
int u = -1, minD = INF; // 分别存放到s距离最小的结点下标和距离
for (int j = 0; j < n; j++) // 遍历所有结点,找到离s最近的结点
{
if (visit[j] == false && d[j] < minD)
{
u = j;
minD = d[j];
}
}
if (u == -1) // 不存在最近结点,即s与所有未访问结点都不连通
return;
visit[u] = true; // 找到最近结点,并标记已访问
for (int j = 0; j < adj[u].size(); j++) // 以u结点为新的接入点,更新未访问结点到起点的最小距离
{
int v = adj[u][j].v; // 结点编号
int l = adj[u][j].l; // 距离
// 更新距离要满足:该结点与u结点连通;未访问;以u为接入点比直接与起始结点相连更近
if (visit[v] == false && d[u] + l < d[v])
{
d[v] = d[u] + l;
pre[v] = u;
}
}
}
}
输出最短路径,只要递归输出pre数组即可
void DFS(int s, int now) // s为起始结点,now为当前访问结点
{
if (s == now)
{
printf("%d", s);
return;
}
DFS(s, pre[now]);
printf("%d", now);
}