1找到最短距离已经确认的顶点,从它出发更新相邻顶点的最短距离
2此后不需要关心1中的“最短距离已经确认的顶点”
堆中元素共有O(V)个,更新和取出都有O(E)次,每次更新或取出堆的维护时间是O(logV),因此该算法的时间复杂度为O(ElogV).
输入两个整数V,E,分别表示有向图(无向图就多添加一倍的边)的的节点数,和边数
接下来E行,每行三个整数,分别表示,无向图边的连个端点以及权值
输出一行V个整数,表示每个点到起点的最短路径
7 10
1 2 2
1 3 5
2 3 4
3 4 2
2 4 6
4 6 1
2 5 10
5 6 3
5 7 5
6 7 9
有向:0 2 5 7 12 8 17
无向:0 2 5 7 11 8 16
#include
#include
#include
using namespace std;
const int MAX_V=10005;
const int INF=0x3f3f3f;
struct edge{
int to;//边的终点
int cost;//权值
edge(int t,int c){
to=t;
cost=c;
}
};
typedef pair P;//first是最短距离,second是顶点编号
int V;//顶点数
int E;//边数
vector G[MAX_V];
int d[MAX_V];
void read(){
int start,to,cost;
scanf("%d%d",&V,&E);
for(int i=0;i参数,堆按照first从小到大的顺序取出值
priority_queue,greater
> que;//优先队列里存的都是最短距离已经确认的顶点
fill(d,d+V+1,INF);
d[s]=0;
que.push(P(0,s));//起点,起点到起点的最短距离是确定的(0)
while(!que.empty()){
P p=que.top();que.pop();//每次取出容器中已经确定的离起点最近的点
printf("取出点%d\n",p.second);
int v=p.second;
if(d[v]
d[v]+e.cost){
printf("d[%d]:%d>d[%d]:%d+%d_to_%d_cost:%d\t更新d[%d]为%d\t%d入队\n",e.to,d[e.to],v,d[v],v,e.to,e.cost,e.to,d[v]+e.cost,e.to);
d[e.to]=d[v]+e.cost;//d[v]是已经确定的
que.push(P(d[e.to],e.to));//更新后最短距离已经确认的点入队,优先队列里自动维护,队头是最小的那个
}
}
}
}
int main(){
read();
dijkstra(1);
for(int i=1;i<=V;i++)
printf("%d ",d[i]);
return 0;
}
下面为注释更详细的版本
/*
7 10
1 2 2
1 3 5
2 3 4
3 4 2
2 4 6
4 6 1
2 5 10
5 6 3
5 7 5
6 7 9
0 2 5 7 12 8 17
*/
#include
#include
#include
using namespace std;
const int MAX_V=10005;
const int INF=0x3f3f3f;
struct edge{
int to;//边的终点
int cost;//权值
edge(int t,int c){
to=t;
cost=c;
}
};
typedef pair P;//first是该点入队时的最短距离,second是顶点编号
int V;//顶点数
int E;//边数
vector G[MAX_V];
int d[MAX_V];
void read(){
int start,to,cost;
scanf("%d%d",&V,&E);
for(int i=0;i参数,堆按照first从小到大的顺序取出值
priority_queue,greater
> que;//优先队列里存的都是最短距离已经确认的顶点
/*
priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数:
priority_queue
其中Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.
STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,
优先队列就是大顶堆,队头元素最大。
如果要用到小顶堆,则一般要把模板的三个参数都带进去。
STL里面定义了一个仿函数 greater<>,对于基本类型可以用这个仿函数声明小顶堆
p1 < p2; 两个pair对象间的小于运算,其定义遵循字典次序:如
p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回true。
pair详解 转https://blog.csdn.net/sevenjoin/article/details/81937695
*/
fill(d,d+V+1,INF);
d[s]=0;
que.push(P(0,s));//起点,起点到起点的最短距离是确定的(0)
while(!que.empty()){
P p=que.top();que.pop();//每次取出容器中已经确定的离起点最近的点
//printf("取出点%d\n",p.second);
int v=p.second;
if(d[v]d[1]:0+1_to_2_cost:2 更新d[2]为2 2入队
d[3]:4144959>d[1]:0+1_to_3_cost:5 更新d[3]为5 3入队
取出点2
d[4]:4144959>d[2]:2+2_to_4_cost:6 更新d[4]为8 4入队
d[5]:4144959>d[2]:2+2_to_5_cost:10 更新d[5]为12 5入队
取出点3
d[4]:8>d[3]:5+3_to_4_cost:2 更新d[4]为7 4入队
取出点4 这个是P(7,4)
d[6]:4144959>d[4]:7+4_to_6_cost:1 更新d[6]为8 6入队
取出点4 这个是P(8,4),而d[4]已经在第65行时被更新为7d[6]:8+6_to_7_cost:9 更新d[7]为17 7入队
取出点5
取出点7
*/
for(int i=0;id[v]+e.cost){
//printf("d[%d]:%d>d[%d]:%d+%d_to_%d_cost:%d\t更新d[%d]为%d\t%d入队\n",e.to,d[e.to],v,d[v],v,e.to,e.cost,e.to,d[v]+e.cost,e.to);
d[e.to]=d[v]+e.cost;//d[v]是已经确定的
que.push(P(d[e.to],e.to));//更新后最短距离已经确认的点入队,优先队列里自动维护,队头是最小的那个
}
}
}
}
int main(){
read();
dijkstra(1);
for(int i=1;i<=V;i++)
printf("%d ",d[i]);
return 0;
}
参考资料:挑战程序设计竞赛P102