代码写的很详细了而且精短,说说我个人的理解:
首先用优先队列快速查找最小值,但考虑到原来队列中已经有的值不方便清除,所以标记每个点的first表示最短路径当一个点重复出现时只需要判断是否时我需要的就行了
#include<iostream> #include<vector> #include<queue> 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<int,int> P;//first是最短距离,second是顶点编号 int V;//顶点数 int E;//边数 vector<edge> G[MAX_V]; int d[MAX_V]; void read(){ int start,to,cost; scanf("%d%d",&V,&E); for(int i=0;i<E;i++){ scanf("%d%d%d",&start,&to,&cost); G[start].push_back(edge(to,cost)); G[to].push_back(edge(start,cost));//加上这句,无向图 } } void dijkstra(int s){ //通过指定greater<P>参数,堆按照first从小到大的顺序取出值 priority_queue<P,vector<P>,greater<P> > 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]<p.first)continue;//表示该点入队不只一次(即之前有多个点都可以到达它),那么d[v]也可能更新了不只一次, //而每次更新都会使d[v]更小,显然这个p.first是其中一次更新,但不是最小的那个,而最小的 //那个在此之前就出队了,所以不必再用这条记录继续往下更新了 for(int i=0;i<G[v].size();i++){//扫描其所有相邻的顶点,并更新他们的最短距离d[i] edge e=G[v][i]; if(d[e.to]>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; }