题目背景
2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100→60100 \rightarrow 60100→60 ;
Ag→CuAg \rightarrow CuAg→Cu ;
最终,他因此没能与理想的大学达成契约。
而其实,这样的同学不只一位,小 F 就认识两位。
小 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≤N≤1000001;
1≤M≤2000001;
1≤ui,vi,S≤N;
0≤wi≤1050;
0≤∑wi≤1090 。
题解:
堆优化迪杰斯特拉,不要犹豫,SPFA会被卡成n^2的。其中,加入判断点是否松弛过的数组,判断后使用continue,还有快读也必不可少。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #define pi pair<int,int> using namespace std; const int maxn=100001,maxm=500003; int n,m,S; int fir[maxn],nex[maxm],w[maxm],to[maxm],fa[maxn],vis[maxn]; long long dis[maxn]; priority_queue<pi,vector<pi>,greater<pi> >q; int read() { int X=0,w=1; char c=getchar(); while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); } while (c>='0'&&c<='9') X=(X<<3)+(X<<1)+c-'0',c=getchar(); return X*w; } void mem() { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { dis[i]=2147483647; fa[i]=0; } dis[S]=0; } void Dijkstra() { mem(); q.push(make_pair(0,S)); while(!q.empty()) { int k=q.top().second; q.pop(); if(vis[k]) continue; vis[k]=true; for(int i=fir[k];i!=-1;i=nex[i]) { if(vis[to[i]])continue; if(dis[to[i]]>dis[k]+w[i]) { dis[to[i]]=dis[k]+w[i]; fa[to[i]]=k; q.push(make_pair(dis[to[i]],to[i])); } } } } int main() { memset(fir,-1,sizeof(fir)); memset(vis,0,sizeof(vis)); n=read(),m=read(),S=read(); int x,y,z; for(int i=1;i<=m;i++) { x=read(),y=read(),z=read(); w[i]=z; to[i]=y; nex[i]=fir[x]; fir[x]=i; } Dijkstra(); for(int i=1;i<=n;i++) { printf("%lld",dis[i]); if(i!=n)printf(" "); } return 0; }