p4779(最短路模板)

2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。

然后呢?

100→60100 \rightarrow 60100→60 ;

Ag→CuAg \rightarrow CuAg→Cu ;

最终,他因此没能与理想的大学达成契约。

小 F 衷心祝愿大家不再重蹈覆辙。

题目描述

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

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

输入输出格式

输入格式:

 

第一行为三个正整数 N,M,SN, M, SN,M,S 。 第二行起 MMM 行,每行三个非负整数 ui,vi,wiu_i, v_i, w_iui​,vi​,wi​ ,表示从 uiu_iui​ 到 viv_ivi​ 有一条权值为 wiw_iwi​ 的边。

 

输出格式:

 

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

 

输入输出样例

输入样例#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≤1000001 \leq N \leq 1000001≤N≤100000 ;

1≤M≤2000001 \leq M \leq 2000001≤M≤200000 ;

S=1S = 1S=1 ;

1≤ui,vi≤N1 \leq u_i, v_i\leq N1≤ui​,vi​≤N ;

0≤wi≤1090 \leq w_i \leq 10 ^ 90≤wi​≤109 ,

0≤∑wi≤1090 \leq \sum w_i \leq 10 ^ 90≤∑wi​≤109 。

本题数据可能会持续更新,但不会重测,望周知。

 

1.就是dj用优先队列优化(结构体的优先队列还是应该多写啊,改了好多次orz)

2.然后用优先队列有一个大坑:

重点重点:一般的dj是松弛n次就好,但是用了优先队列一个点可能会出现多次,(比如你1\rightarrow3,使得dist[3]减小入队,后面可能2\rightarrow3又一次入队,那这样3可能两次在q.top)所以循环应该是while(!q.empty()),再加上一个if(dick.w!=dist[mid])continue的优化就可以了.

 

ac代码:

#include<iostream>
#include<cstdio>
#include<queue>

using namespace std;

long int n,m,s,mid,mid1,dist[100050],head1[100050];
struct data
{
	long int head,to,w;
};
bool operator <(data a,data b)
	{ 
		return a.w>b.w;
	}
data dick,edge[200050];
priority_queue <data> q;
void init()
{
	scanf("%ld%ld%ld",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		scanf("%ld%ld%ld",&mid,&edge[i].to,&edge[i].w);
		edge[i].head=head1[mid];
		head1[mid]=i;
	}
}
void dis()
{
	for(int i=1;i<=n;i++) dist[i]=0x7fffffff;
	dist[s]=0;dick.w=0;dick.head=s;q.push(dick);
	while(!q.empty())
	{
		dick=q.top();q.pop();
		//cout<<dick.head<<endl;
		mid=dick.head;mid1=head1[mid];
		if(dick.w!=dist[mid]) continue;
		while(mid1)
		{
			if(dist[edge[mid1].to]>dist[mid]+edge[mid1].w)
			{
				dist[edge[mid1].to]=dist[mid]+edge[mid1].w;
				dick.head=edge[mid1].to;dick.w=dist[edge[mid1].to];
				q.push(dick);
			}
			mid1=edge[mid1].head;
		}
	}
	
}
int main()
{
	init();
	dis();
	for(int i=1;i<=n;i++) printf("%ld ",dist[i]);
} 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值