堆优化的dijkstra算法

d i j k s t r a dijkstra dijkstra算法简述:

定义 d i s [ i ] dis[i] dis[i]表示节点 i i i到起点的距离

d i s [ i ] dis[i] dis[i]在初始时,除起点外,全部为极大值

每一次寻找 d i s [ i ] m i n dis[i]_{min} dis[i]min,并用其更新与之相连的每个节点。

伪代码:

for(每个顶点)找出dis最小的顶点x(没有访问过);
for(每个与x相连的顶点y)
	dis[y]=min(dis[y],dis[x]+x与y相连边的边权)
}

考虑优化寻找 d i s m i n dis_{min} dismin的过程:每次都要 O ( n ) O(n) O(n)比较每个顶点

使用优先队列( p r i o r i t y _ q u e u e priority \_ queue priority_queue): O ( l o g 2 n ) O(log_{2}n) O(log2n)得到 d i s [ i ] dis[i] dis[i]最小值

p a i r pair pair存储。first设为 d i s [ i ] dis[i] dis[i] s e c o n d second second设为 i i i(自动按照 f i r s t first first排序)

由于 p r i o r i t y _ q u e u e priority \_ queue priority_queue默认为大根堆(即从大到小排序),可以将 d i s [ i ] dis[i] dis[i]全部置为相反数,就会从小到大排序了。当然,也可以直接更改 p r i o r i t y _ q u e u e priority \_ queue priority_queue本身的定义。

即设为 p r i o r i t y _ q u e u e < p a i r , v e c t o r < p a i r < i n t , i n t > > , g r e a t e r < p a i r < i n t , i n t > > > priority \_ queue<pair,vector<pair<int,int> >,greater<pair<int,int> > > priority_queue<pair,vector<pair<int,int>>,greater<pair<int,int>>>

例题:洛谷P4779单元最短路径(标准版)

#include<bits/stdc++.h>
using namespace std;
int n,m,s;
struct Edge{
	int next,w,to;
}e[200007];
int e_cnt,head[100007];
int d[100007],vis[100007];
priority_queue<pair<int,int> > q;
int Read(){
	char ch=getchar();
	int flag=1,res=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-')flag=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		res=res*10+ch-'0';
		ch=getchar();
	}
	return flag*res;
}
void add_edge(int u,int v,int w){
	e[++e_cnt].next=head[u];
	e[e_cnt].to=v;
	e[e_cnt].w=w;
	head[u]=e_cnt;
	return;
}
int main(){
	memset(d,0x3f,sizeof(d));
	memset(vis,0,sizeof(vis));
	n=Read();m=Read();s=Read();
	for(int i=1;i<=m;++i){
		int u=Read(),v=Read(),w=Read();
		add_edge(u,v,w);
	}
	d[s]=0;
	q.push(make_pair(0,s));
	while(!q.empty()){
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;//记得判断
		vis[x]=1;
		for(int i=head[x];i;i=e[i].next){
			int y=e[i].to,z=e[i].w;
			if(d[x]+z<d[y]){
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));
			}
		}
	}	
	for(int i=1;i<=n;++i)
		printf("%d ",d[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值