P4779 【模板】单源最短路径(标准版)——链式前向星

题目链接:【模板】单源最短路径(标准版) - 洛谷

题目背景

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

然后呢?

100 \rightarrow 60100→60;

\text{Ag} \rightarrow \text{Cu}Ag→Cu;

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

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

题目描述

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

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

输入格式

第一行为三个正整数 n, m, sn,m,s。 第二行起 mm 行,每行三个非负整数 u_i, v_i, w_iui​,vi​,wi​,表示从 u_iui​ 到 v_ivi​ 有一条权值为 w_iwi​ 的有向边。

输出格式

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

输入输出样例

输入 #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 \leq n \leq 10^51≤n≤105;

1 \leq m \leq 2\times 10^51≤m≤2×105;

s = 1s=1;

1 \leq u_i, v_i\leq n1≤ui​,vi​≤n;

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

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

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

2018.09.04 数据更新 fr

解题思路:

这题主要是dijkstra算法+优化。刚开始使用邻接矩阵建图,可想而知在大量数据下超时了。后面去学习了一下链式前向星(观看是博客主m_little horse的文章,非常细致,平生第一次看懂了链式前向星,推荐大家去看。文章链接:http://t.csdn.cn/veqjp),用优先队列存储中间点。正当我觉得一切都很完美的时候,超时给我来了重重一锤。(陷入沉思:为啥还超时,都优化成这样了,是不是数据太刁钻了)不信邪,去看了大家ac的代码,发现输入输出都是用scanf()和printf()。cin和cout用久了,都忘记了它的时间消耗太大了。改完后过了几个测试点,还有几个一直超时。发现数组长度开小了,最最最后终于过了。

注意事项总结:1、链式前向星建图,优先队列存储中间点

                         2、输入输出用scanf()和printf()。不要用cin和cout会超时

                         3、数组长度一定要看清题目所给范围,不要开小了

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,s;
const int MaxN=100010,MaxM=200010,Max=0x7fffffff;
int head[100005],cnt=0;
int dis[MaxN],vis[MaxN];
struct edge{
	int v;//终点
	int w;//权值 
	int next;//下一条边 
};
edge e[MaxM];
struct cmp{
	bool operator()(edge a,edge b){
		return a.w>b.w;//排序法则与sort相反 
	}
};
void add(int u,int v,int w){//加边 
	++cnt;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void dijkstra(){
	priority_queue<edge,vector<edge>,cmp > pq;
	int v,w,f;
	edge tmp; 
	pq.push({s,0,-1});
	while(!pq.empty()){
		tmp=pq.top();
		v=tmp.v;
		pq.pop();
		if(vis[v]!=0) continue;
		vis[v]=1;
		f=v;
		for(int i=head[f];i!=-1;i=e[i].next){
			v=e[i].v;
			w=e[i].w;
			if(dis[v]>dis[f]+w){
				dis[v]=dis[f]+w;
				if(vis[v]==0)pq.push({v,dis[v],head[f]});
				//cout<<i<<","<<s<<"->"<<f<<"->"<<v<<":"<<w<<","<<dis[v]<<endl;
			}
		}
	}	
}
int main(){
	scanf("%d%d%d",&n,&m,&s);
	int u,v,w;
	for(int i=1;i<=n;i++){
		head[i]=-1;
		vis[i]=0;
		dis[i]=Max;
	}
	dis[s]=0;
	while(m--){
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	dijkstra(); 
	for(int i=1;i<=n;i++){
		printf("%d ",dis[i]);
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值