题目背景
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 数据更新 from @zzq
思路:这道题会故意卡掉SPFA算法,因此我们需要采用优化版的Dijkstra算法。
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define ll long long
#define mod 1000000007
#define maxn 500050
int n,m,start,vis[maxn];
ll dis[maxn];
struct node{
int to;
ll val;
node(int to,ll val):to(to),val(val){}
};
struct cmp{
bool operator()(node a,node b){
return a.val>b.val;
}
};
priority_queue<node,vector<node>,cmp> qq;
vector<node> q[maxn];
int main(void){
int x,y,z;
scanf("%d%d%d",&n,&m,&start);
for(int i=0;i<m;i++){
scanf("%d%d%d",&x,&y,&z);
q[x].push_back(node(y,z));
}
for(int i=1;i<=n;i++)
dis[i]=(1<<31)-1;
dis[start]=0;
qq.push(node(start,0));
while(!qq.empty()){
node now=qq.top();
qq.pop();
if(vis[now.to])
continue;
vis[now.to]=1;
for(int i=0;i<q[now.to].size();i++){
int v=q[now.to][i].to;
ll val=q[now.to][i].val;
if(dis[v]>dis[now.to]+val){
dis[v]=dis[now.to]+val;
if(!vis[v])
qq.push(node(v,dis[v]));
}
}
}
for(int i=1;i<n;i++)
printf("%lld ",dis[i]);
printf("%lld\n",dis[n]);
return 0;
}