题目描述
给定 NN 个点和 MM 条单向道路,每条道路都连接着两个点,每个点都有自己编号,分别为 1∼N1∼N 。
问你从 SS 点出发,到达每个点的最短路径为多少。
输入描述
输入第一行包含三个正整数 N,M,SN,M,S。
第 22 到 M+1M+1 行每行包含三个正整数 u,v,wu,v,w,表示 u→vu→v 之间存在一条距离为 ww 的路。
1≤N≤5×1031≤N≤5×103,1≤M≤5×1041≤M≤5×104,1≤ui,vi≤N1≤ui,vi≤N,0≤wi≤1090≤wi≤109。
本题数据随机生成。
输出描述
输出仅一行,共 NN 个数,分别表示从编号 SS 到编号为 1∼N1∼N 点的最短距离,两两之间用空格隔开。(如果无法到达则输出 −1−1)
输入输出样例
示例 1
输入
3 3 1
1 2 1
1 3 5
2 3 2
输出
0 1 3
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,m,s;
const int N=3e5+10;
typedef long long LL;
typedef pair<int,int> PII;//存储边的信息
vector <PII> adj[N];//邻接表,存储每条边的信息
LL dist[N];//s到节点的最短距离
bool visited[N];//标记是否被访问过
void dijkstra(int start)
{
//初始化距离数组和访问数组
fill(dist,dist+N,LLONG_MAX);
memset(visited,false,sizeof(visited));
//s到s的距离为0
dist[s]=0;
//定义一个优先队列
priority_queue<PII,vector<PII>,greater<PII> > pq;
//将源点入队
pq.push({0,s});
//当队列不为空
while(!pq.empty())
{
//取出队头信息,队头永远是最小得到那个
//队头节点编号
auto t=pq.top();
//弹出
pq.pop();
//队头节点编号
int u=t.second;
//如果该节点被标记过,则跳过
if(visited[u]==true) continue;
//标记队头节点
visited[u]=true;
//遍历队头节点的所有邻接点
for(int j=0;j<adj[u].size();j++)
{
//取出邻接点信息
//邻接点编号
int v=adj[u][j].second;
LL weight=adj[u][j].first;
if(dist[u]+weight < dist[v])
{
dist[v]=dist[u]+weight;
//将更新后的邻接点入队
pq.push({dist[v],v});
}
}
}
}
int main()
{
cin>>n>>m>>s;
//将各点存入邻接表
while(m--)
{
int u,v,w;
cin>>u>>v>>w;
adj[u].push_back({w,v});
}
dijkstra(s);//从s开始松弛
for(int i=1;i<=n;i++)
{
if(dist[i]==LLONG_MAX)
cout<<-1<<" ";
else
cout<<dist[i]<<" ";
}
return 0;
}