优先队列优化dij

优先队列优化dij

例题: 洛谷4779

题目描述

给定一个 NN 个点,MM 条有向边的带非负权图,请你计算从 SS 出发,到每个点的距离。

数据保证你能从 SS 出发到任意点。

输入格式

第一行为三个正整数 N, M, S。 第二行起 MM 行,每行三个非负整数 ui,vi,w,表示从 ui到 vi有一条权值为 wi 的边。

输出格式

输出一行 N个空格分隔的非负整数,表示 S到每个点的距离。

输入输出样例

输入#1
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出#1
0 2 4 3	
说明/提示

1≤N≤100000;

1≤M≤200000;

S=1;

1≤ui,vi ≤N;

wi ≤10^9 ,

0≤∑wi≤10^9 。

思路

简单的单源最短路模板题 直接上板子就完事了

//https://www.luogu.org/problem/P4779 
#include<map>
#include<cmath>
#include<cstdio>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<queue>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL read()
{
	LL x=0,w=1;
	char ch=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
		{
			w=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return w*x;
}
int n,m,s;
int ui,vi,wi;
int cnt,head[100005],d[100005];
struct node{
	int to,next,w;
};
node edge[200005];
void add(int x,int y,int w)
{
	edge[++cnt].to=y;
	edge[cnt].next=head[x];
	edge[cnt].w=w;
	head[x]=cnt;
}
struct nn{
	int x,dis;
	bool operator <(const nn& b)const//重载运算符'<' 
	{
		return dis>b.dis;//顺序按照dis从小到大排(此处与sort的cmp恰好相反) 
	}
};//记录入队的节点和距离 
priority_queue < nn > q;
inline nn init(int xx,int dd)
{
	nn t;
	t.x=xx;
	t.dis=dd;
	return t;
}
nn now;
void dij(int s)
{
	for(register int i=1;i<=n;i++)//初始化 
	{
		d[i]=INF;
	}
	d[s]=0;//d[x]代表点s到 x的距离 
	now.x=s;
	now.dis=0;
	q.push(now);
	while(!q.empty())
	{	
		now=q.top();
		q.pop();
		if(now.dis>d[now.x])//优化 如果该边权大于到点now.x的距离 说明该边比已有点更差就没有必要去遍历该点了  
			continue ;
		for(register int i=head[now.x];i!=0;i=edge[i].next)//遍历当前now点所连接的所有边 
		{
			if(d[edge[i].to]>d[now.x]+edge[i].w)//如果该边比已有点更优 则对该边所连的点进行松弛,并将该点入列 
			{
				d[edge[i].to]=d[now.x]+edge[i].w;
				q.push(init(edge[i].to,d[edge[i].to]));
			}
		}
	}
}
int main()
{
	n=read();
	m=read();
	s=read();
	for(register int i=1;i<=m;i++)
	{
		ui=read();
		vi=read();
		wi=read();
		add(ui,vi,wi);
	}
	dij(1);
	for(register int i=1;i<=n;i++)
	{
		cout<<d[i]<<' ';
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值