优先队列——最短路径

/*
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<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));
	}
}
void dijkstra(int s){
    //通过指定greater<P>参数,堆按照first从小到大的顺序取出值
	priority_queue<P,vector<P>,greater<P> > que;//优先队列里存的都是最短距离已经确认的顶点 
    /*
    priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数:
    priority_queue<Type, Container, Functional>
    其中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]<p.first)continue;//表示该点入队不只一次(即之前有多个点都可以到达它),那么d[v]也可能更新了不只一次,
					//而每次更新都会使d[v]更小,显然这个p.first是其中一次更新,但不是最小的那个,而最小的
					//那个在此之前就出队了,所以不必再用这条记录继续往下更新了 
		
		/*
		这里是队的取出情况 
		取出点1
		d[2]:4144959>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行时被更新为7<p.first:8 所以continue 
		取出点6
		d[7]:4144959>d[6]:8+6_to_7_cost:9       更新d[7]为17    7入队
		取出点5
		取出点7
		*/
		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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值