Dijksta算法:
Dijksta算法相比于Bellman-Ford算法,效率提高了许多,但是不能解决带有负权值的图,所以要根据具体问题采取相应的算法,即有负权值的图只能用Bellman-Ford算法,如果权值是非负的,那么我们就选择Dijksta算法,效率高嘛。
分析:
1.找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离。
2.此后不需要再关心1中的“最短距离已经确定的顶点”。
在最开始的时候,只有起点的最短距离是确定的,而在尚未使用过的顶点中,距离d[i]最小的顶点就是最短距离已经确定的顶点。
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1000+10;
const int INF = 99999999;
int cost[maxn][maxn];//cost[u][v]表示边e=(u,v)的权值
int d[maxn]; //顶点s出发的最短距离
bool used[maxn]; //已经使用过的图
int V,E; //顶点数,边数
/*初始化*/
void init()
{
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (i == j) {
cost[i][j] = 0;
}
else {
cost[i][j] = INF;
}
}
}
}
void dijkstra(int s)
{
for(int i=0; i<V; i++)
{
d[i] = INF;
used[i] = false;
}
d[s] = 0;
while(true)
{
int v = -1;
//从尚未使用过的顶点中选择一个距离最小的顶点
for(int u = 0; u < V; u++)
{
if(!used[u] && (v == -1 || d[u] < d[v])) v = u;
}
if(v == -1) break; //所有边都访问过,则退出
used[v] = true;
for(int u = 0; u < V; u++)
{
d[u] = min(d[u], d[v] + cost[v][u]);
}
}
}
int main()
{
scanf("%d%d",&V,&E);
int s,t,c;
init();
for(int i=0;i<E;i++)
{
scanf("%d%d%d",&s,&t,&c);
cost[s][t] = cost[t][s] = c;
}
dijkstra(0);
for(int i=0;i<V;i++)
printf("%d ",d[i]);
return 0;
}
优化
下面需要优化的是数值的插入和取出最小值两个操作。使用堆就可以了。把每个顶点当前的最短距离用堆来维护,在更新最短距离时,把对应的元素忘根的方向移动以满足堆的性质。每次从堆中取出的最小值就是下一次要使用的顶点。下面使用STL中的priority_queue来实现,优先队列通过优先级的先后来排队,这样在每次更新时往堆里插入当前最短距离和顶点的值。
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 1000;
const int INF = 99999999;
struct edge{
int to,cost;
edge(int to, int cost) : to(to), cost(cost){}
};
typedef pair<int,int> P;//first是最短路径,second是顶点的编号
int d[maxn];
int V,E;
vector<edge> G[maxn];
void dijkstra(int s)
{
priority_queue<P,vector<P>,greater<P> > q;
fill(d, d + V, INF);
d[s] = 0;
q.push(P(0,s));
while(!q.empty())
{
P p = q.top(); q.pop();
int v = p.second;
if(d[v] < p.first) continue;
for(int i=0; i<G[v].size(); i++)
{
edge e = G[v][i];
if(d[e.to] > d[v] + e.cost)
{
d[e.to] = d[v] + e.cost;
q.push(P(d[e.to],e.to));
}
}
}
}
int main()
{
scanf("%d%d",&V,&E);
int s,t,c;
for(int i=0;i<E;i++)
{
scanf("%d%d%d",&s,&t,&c);
G[s].push_back(edge(t,c));
}
dijkstra(0);
for(int i=0; i<V; i++)
{
printf("%d ",d[i]);
}
return 0;
}