基本思想
通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。
此外,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。
初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是"起点s到该顶点的路径"。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 ... 重复该操作,直到遍历完所有顶点。
操作步骤
(1) 初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
(2) 从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。
(3) 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
(4) 重复步骤(2)和(3),直到遍历完所有顶点。
单纯的看上面的理论可能比较难以理解,下面通过实例来对该算法进行说明。
迪杰斯特拉算法图解
例题:hdu最短路
题意送衣服,给你一定的点和点的值和权值,然后要你找到怎么最短送到终点。直接模版代入就行了
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF=200000000;
const int maxnum = 105;
const int maxint = 1001;
int map[maxint][maxint];
int vist[maxint],dow[maxint],ans[maxint];
void dijkstra(int s,int n)
{
int i,j,k,minx;
memset(vist,0,sizeof(vist));
for(i=1;i<=n;i++)
{
ans[i]=map[s][i];
}
dow[s]=0;
vist[s]=1;
for(i=1;i<n;i++)//注意不能等于n,距离比点的数量少一
{
minx=INF;
for(j=1;j<=n;j++)
{
if(minx>ans[j]&&!vist[j])
{
minx=ans[j];//找出第一个最短点
k=j;
}
}
dow[k]=minx;
vist[k]=1;
for(j=1;j<=n;j++)
{
if(!vist[j]&&ans[j]>map[k][j]+dow[k])//找剩下的点的长度
{
ans[j]=map[k][j]+dow[k];
}
}
}
}
int main()
{
// 记录图的两点间路径长度
int n, m; // 图的结点数和路径数
while(scanf("%d %d", &n, &m) && (n || m))
{
int u, v, w; // 输入p, q两点及其路径长度
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
map[i][j] =(i==j?0:INF);
for(int i=1; i<=m; ++i)
{
cin >> u>> v>> w;
map[u][v] =map[v][u] = w; // q指向p,这样表示无向图
}
for(int i=1; i<=n; ++i)
ans[i] = maxint;
dijkstra(1,n);
cout << ans[n]<< endl;
}
return 0;
}