一、Dijkstra算法策略
(1)数据结构
n:城市顶点个数,m:城市间路线的条数。
map[][]:地图对应的带权邻接矩阵。
dist[][]:记录源点u到某个顶点的最短路径长度。
p[]:记录源点到某个顶点的最短路径上的该顶点的前一个顶点(即前驱结点)。
flag[i]:其值为true时说明顶点i 已经加入到集合S,否则顶点i属于集合V-S。
(集合S包含的顶点特点:dist[i]即从源点到顶点i的最短路径长度为最后的最短长度,即最简化;集合V代表全部顶点)
const int N = 100;//初始化城市的个数,可以修改
const int INF = 1e7; //即1*(10^7)无穷大
int map[N][N],dist[N],p[N],n,m;
bool flag[N];
(2)初始化源点u到其他各个顶点的最短路径长度,初始化源点u出边邻结点(即u可直达的其他的顶点t)的前驱为u;
bool flag[n];
for(int i = 1;i <= n;i++)
{
dist[i] = map[u][i];//初始化源点u到其他各个顶点的最短路径长度
flag[i] = false;
if(dist[i] == INF)
p[i] = -1;
else
p[i] = u;
}
(3)初始化集合S,令集合S={u},从源点到u(即u到u)的最短路径为0.
flag[u] = true;//集合S={u}
dist[u] = 0;//从源点到u(即u到u)的最短路径为0
(4)找最小,加入S集合
在集合V-S中寻找距离源点u的距离最短的顶点t,如果找不到t,则说明u=t,可以跳出循环结束;否则,将t加入集合S。
int temp = INF,t = u;
for(int j=1;j<=n;j++)
if( !flag[j] && dist[t] < temp) // !flag[j]即不在集合S里面的顶点
{
t = j; //记录下来
temp = dist[t]; //记录最小值,和下一个比较
}
if(t == u)
return;
flag[t] = true; //将t加入集合S
(5)借东风(距离源点u的距离最短的顶点是t)
考查集合V-S中源点u到t的邻接点j的距离,即map[t][j]的距离,如果源点u经过t到达j的路径更短,则更新dist[j],即dist[j]=dist[t]+map[t][j];即松弛操作,并记录j的前驱结点t。
for(int j=1;j<=n;j++)
if( !flag[j] && map[t][j]<INF)
if(dist[j] > dist[t]+map[t][j])
{
dist[j]=dist[t]+map[t][j];
p[j]=t;
}
(6)重复(4)~(5),直到结束。
二、代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<Windows.h>
#include<stack>
using namespace std;
const int N = 100;//城市的个数可以修改
const int INF = 1e7;//初始化无穷大
int map[N][N], dist[N], p[N], n, m;//城市的个数n,城市间路线的条数m
bool flag[N];//其值为true时说明顶点i 已经加入到集合S,否则顶点i属于集合V-S。
void Dijkstra(int u)
{
int i,j;
for ( i = 1; i <= n; i++)
{
dist[i] = map[u][i]; //初始化源点u到其他各个顶点的最短路径长度
flag[i] = false;
if (dist[i] == INF)
p[i] = -1;
else
p[i] = u;
}
dist[u] = 0;
flag[u] = true;
//在集合V-S中寻找距离源点u的距离最短的顶点t,如果找不到t,则说明u=t,可以跳出循环结束;否则,将t加入集合S。
for ( i = 1; i <= n; i++)
{
int temp = INF, t = u;
for ( j = 1; j <= n;j++)
if (!flag[j] && dist[j] < temp)
{
t = j;
temp = dist[j];
}
if (t == u)
return;
flag[t] = true;//将t加入集合S
/*考查集合V - S中源点u到t的邻接点j的距离,即map[t][j]的距离,
如果源点u经过t到达j的路径更短,则更新dist[j],即dist[j] = dist[t] + map[t][j];即松弛操作,并记录j的前驱结点t。*/
for ( j = 1; j <= n; j++) //距离源点u的距离最短的顶点是t
{
if (!flag[j] && dist[j] > dist[t] + map[t][j])
{
dist[j] = dist[t] + map[t][j];
p[j] = t;
}
}
}
}
//显示最短路径上经过了哪些城市
void findpath(int u)
{
int x;
int i;
stack<int> s;//创建一个栈s
cout << "源点为:" << u << endl;
for ( i = 1; i <= n; i++)//从源点到每一个顶点
{
x = p[i];
while (x != -1)
{
s.push(x);//将前驱依次压入栈中
x = p[x];
}
cout << "源点到其他各顶点最短路径为;" ;
while (!s.empty())
{
cout << s.top() << "--";//依次取出栈顶元素
s.pop();//出栈
}
cout << i << ";最短距离为:"<< dist[i] << endl;
}
}
int main()
{
int u, v, w, st;
int i;
system("color 0d");
cout << "请输入城市的个数:" << endl;
cin >> n;
cout << "请输入城市之间的路线个数:" << endl;
cin >> m;
cout << "请输入城市之间的路线以及距离:" << endl;
for ( i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
map[i][j] = INF;
}
while (m--)
{
cin >> u >> v >> w;
map[u][v] = min(map[u][v], w); //邻接矩阵储存,保留最小的距离
}
cout << "请输入小明所在的位置:" << endl;
cin >> st;
Dijkstra(st);
cout << "小明所在的位置:" << st << endl;
for ( i = 1; i <= n; i++)
{
cout << "小明:" << st << "-" << "要去的位置:" << i << endl;
if (dist[i] == INF)
cout << "sorry,无路可走" << endl;
else
cout << "最短距离为:"<< dist[i]<< endl;
}
findpath(st); //其他输出
return 0;
}
三、复杂度
(1)时间复杂度为:O(n^2)
(2)空间复杂度为:O(n)