题目描述
给定一个 N 个点, M 条有向边的带非负权图,请你计算从 S 出发,到每个点的距离。
数据保证你能从 S 出发到任意点。
输入格式:
第一行为三个正整数 N,M,S 。 第二行起 M 行,每行三个非负整数 ui, vi, wi,表示从 ui到 vi 有一条权值为 wi 的边。
输出格式:
输出一行 N 个空格分隔的非负整数,表示 S 到每个点的距离。
1<=N<=100000
1<=M<=200000
S=1
解题分析:
由于n和m的数据太大,所以这里不能够用普通的dijkstra算法,因为它的复杂度为O(n^2),所以我们这里要用的是复杂度为O(mlog(n))的加上堆优化的dijkstra算法。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string.h>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <map>
#include<stack>
using namespace std;
#define ll long long
#define eps 0.001
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define memset(a,b) memset(a,b,sizeof(a))
const int MAXX=200000+10;
int dis[MAXX];
bool vis[MAXX]; //标记数组
int head[MAXX]; //第一条边的存储位置
struct node
{
int to; //这条边的终点
int cost; //权值
int next; //下一条边的存储位置
} edge[MAXX];
int cnt=0;
struct Node
{
int index; //点的编号
int dis;
};
struct cmp //对存储结构体的优先队列排序
{
bool operator()(const Node &A,const Node &B)
{
return A.dis>B.dis; //按照dis从小到大排序
}
};
priority_queue<Node,vector<Node>,cmp >q;
void add(int a,int b,int c)
{
edge[cnt].cost=c;
edge[cnt].to=b;
edge[cnt].next=head[a];
head[a]=cnt++;
}
void dijkstra(int s,int maxx)
{
memset(dis,INF);
memset(vis,false);
q.push(Node{s,0});
dis[s]=0;
while(!q.empty())
{
int k=q.top().index;
q.pop();
if(vis[k]) //优化
continue;
vis[k]=true; //标记
for(int i=head[k]; ~i; i=edge[i].next) //遍历所有与k相连的点并更新dis
if(dis[k]+edge[i].cost<dis[edge[i].to])
{
dis[edge[i].to]=dis[k]+edge[i].cost;
q.push(Node{edge[i].to,dis[edge[i].to]}); //把这个点的最短距离和编号入队
}
}
}
int main()
{
int n,m,s,a,b,c;
scanf("%d%d%d",&n,&m,&s);
memset(head,-1);
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
dijkstra(1,n);
for(int i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",dis[i]);
else
printf("%d",dis[i]);
}
return 0;
}