Dijkstra算法:
是解决单源最短路径问题的贪心算法,它先求出长度最短路径的一条路径,再参照该最短路劲求出长度次短的一条路径直到求出从源点
到其他各个顶点的最短路径。
Dijkstra算法得基本思想是首先假定源点为u,顶点集合V被划分为两部分:集合S和V-S。初始时S中仅含有源点u,其中S中的顶点到源点的最短路径已经确定。集合V-S中所含有的顶点到源点的最短路径的长度待定,并且用数组dist[]记录当前每个顶点所对应的最短特殊路径长度。
dijkstra算法采用的贪心策略是选择特殊路径长度最短路径,将其连接到V-S中的顶点并将该节点加入到dist[]数组当中,一旦dist[]数组中包含了所有顶点dist[]就是从源点到所有其他顶点之间的最短路径。
数据结构:
(1)设置地图的带权邻接矩阵map[][],即如果从源点u到顶点i有边,就令map[][]等于源点到各个结点的权值
(2)初始化。令集合S={u},对于集合V-S中顶点x,初始化dist [i] =map [u] [ i ]
(3)找最小。在集合V-S中依照贪心策略来寻找使得dist[j]具有最小值的顶点t,
(4)加入集合S中
(5)判结束。如果集合V-S为空,算法结束,否则转6
(6)在(3)中判断找那个已经找到了源点到t的最短路径,那么对集合V-S中所有与顶点t相邻的顶点j,都可以借助t走捷径。如果dist[j]>dist[t]+map[t][j],则dis[j]=dis[t]+map[t][j]记录顶点j的前驱为t,有p[i]=t;用于存储path(路径)。
#include<iostream>
#include<algorithm>
#include<stack>
#define INF 1000
using namespace std;
const int maxn=1000+5;
int dist[maxn];//用于存储源点到各个结点的距离
int map[maxn][maxn];//用于存储各个结点之间的距离
int n,m,k;//输入
int S[maxn];//用于存储结点集合
int p[maxn];//用于存储前驱
void Dijkstra(int u)
{
for(int j=1;j<=n;j++)
{
dist[j]=map[u][j];//将与u结点连接的结点存入dist[];
S[j]=0;//默认结点都没有被访问
if(dist[j]==INF)//如果值为无穷大则可判定为该节点与源节点没有连接
p[j]=-1;//标记为-1
else
p[j]=u;//标记为u
}//预处理
dist[u]=0;
S[u]=1;//将源结点标记为已访问
for(int i=1;i<=n;i++)
{
int temp=INF;
int t=u;
for(int j=1;j<=n;j++)
{
if(temp>dist[j]&&!S[j]==1)
{
temp=dist[j];
t=j;
}
}//找与源结点距离最近的一个结点
if(t==u)
return ;
S[t]=1;//标记为已访问
for(int k=1;k<=n;k++)
{
if(!S[k]==1&&dist[t]+map[t][k]<dist[k]&&map[t][k]<INF)
{
dist[k]=dist[t]+map[t][k];
p[k]=t;
}
}//将该最小结点来判断是否可以让剩下的结点的值更小
}
}
int main()
{
cin>>n>>m;
int a,b,c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=INF;
for(int i=1;i<=m;i++)
{
cin>>a>>b>>c;
map[a][b]=min(map[a][b],c);
}
cin>>k;
Dijkstra(k);
stack<int>s;
for(int i=1;i<=n;i++)
{
int t=p[i];
while(t!=-1)
{
s.push(t);
t=p[t];
}
while(!s.empty())
{
cout<<s.top()<<"->";
s.pop();
}
cout<<i<<" "<<dist[i]<<endl;
}
}
代码优化:
才用优先队列的方式:因为每次选择一个新的结点以后我们就需要更新以下的结点,进行重新排序,所以我们
不妨把每次访问后的结点直接pop出去,再利用queue队列的排序的功能再从队列的顶部取得一个元素,查看之后结点是否可以
继续更新,省去的每次循环都要找最小的步骤。
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=1000;
int flag[maxn];
const int INF=1e7;
int map[maxn][maxn];
int dist[maxn];
int n,m;
struct Node{
int u;
int step;
Node()
{};
Node(int a,int b){
u=a;
step=b;
}
operator < (const Node &a)const{
return step>a.step;
}
};
void DijKstra(int st)
{
priority_queue<Node> Q;
Q.push(Node(st,0));
memset(flag,0,sizeof(flag));
for(int i=1;i<=n;i++)
dist[i]=INF;//这里要初始化为最大值,需要将源点入队。
dist[st]=0;
while(!Q.empty())
{
Node it=Q.top();
Q.pop();
int t=it.u;
if(flag[t])//该节点已经访问过了
continue;
flag[t]=1;
for(int i=1;i<=n;i++)
{
if(!flag[i]&&map[t][i]<INF)
{
if(dist[t]+map[t][i]<dist[i])
{
dist[i]=dist[t]+map[t][i];
Q.push(Node(i,dist[i]));
}
}
}//for
}//while
}
int main()
{
int k;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=INF;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
map[a][b]=min(map[a][b],c);
}
cin>>k;
DijKstra(k);
for(int i=1;i<=n;i++)
{
cout<<k<<"-->"<<i<<":";
if(dist[i]==INF)
cout<<"无路可走"<<endl;
else
cout<<dist[i]<<endl;
}
}//main