Heap_dijkstra
P4779 【模板】单源最短路径(标准版) - 洛谷
题目大意:
给定一个 n n n 节点, m m m 条有向边的带非负权图,请计算从 s t st st 出发,到每个节点的最短路径
思路:
定义 d [ i ] d[i] d[i] 表示 i i i 节点到 s t st st 节点的最短路径
找到一个未被标记的, d [ x ] d[x] d[x] 最小的节点 x x x ,标记 x x x ,并用 x x x 更新所有能够到达的节点,直到所有点被标记
//小根堆可以O(logn)直接找到,优化了1-n的遍历
priority_queue<PII,vector<PII>,greater<PII> > q;
//初始化最初都无法到达d[i]=1e18,每个点还没有被标记vis[i]=0;
for(int i=1;i<=n;i++) d[i]=1e18,vis[i]=0;
//开始时将起点入队
d[st]=0;
q.push({0,st});
while(q.size()){
int u=堆中最小节点;
if(vis[u])//已经确定过就跳过
vis[u]=1;//每次确定一个
进行更新
}
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) x&-x
#define ALL(x) x.begin(),x.end()
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n,m,st;
vector<PII> g[N];
int d[N],vis[N];
void dij(){
priority_queue<PII,vector<PII>,greater<PII> > q;
for(int i=1;i<=n;i++) {
d[i]=1e18;
vis[i]=0;
}
d[st]=0;
q.push({0,st});//{dist,node}
while(q.size()) {
auto x=q.top();
q.pop();
int dt=x.fi,u=x.se;
if(vis[u]) continue;
vis[u]=1;
for(auto v:g[u]) {
int dis=dt+v.se;
int j=v.fi;
if(dis<d[j]){
d[j]=dis;
q.push({d[j],j});
}
}
}
}
void solve() {
cin>>n>>m>>st;
for(int i=1,u,v,x;i<=m;i++){
cin>>u>>v>>x;
g[u].push_back({v,x});
// g[v].push_back({u,x});
}
dij();
for(int i=1;i<=n;i++){
cout<<d[i]<<" ";
}
}
signed main() {
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
while (T--) {
solve();
}
return 0;
}