标签:node DJ int vis edge Debug id dis
part1:dijkstra算法原理
贪心思想。每个点可能被更新多次,但最终每个点在更新成为最优时再取更新其他相邻点。
先看一个 \(DJ\) 代码片段:
struct node{
int id,d;
bool operator <(const node&a)const{
return d>a.d;
}
};
void dijkstra(int st){
for(int i=1;i<=n;i++)
dis[i]=0x3f3f3f3f;
dis[st]=0;
priority_queue<node>q;
q.push((node){st,0});
while(q.size()){
int u=q.top().id;q.pop();
if(vis[u]) continue; vis[u]=1;
for(int e=head[u];e;e=edge[e].nex){
int v=edge[e].to;
if(dis[v]>dis[u]+edge[e].dis){
dis[v]=dis[u]+edge[e].dis;
q.push((node){v,dis[v]});
cnt[v]++;
}
}
}
}
大家猜一猜,若用这份代码跑上图,代码中的cnt[3]
值应该是多少?
一个可能想错的小地方:DJ不是每个点只会被最短的那一条路径更新一次 \(dis\) 吗?所以cnt[3]==1
。实际上答案可能为 \(2\) 。因为在点 \(1\)遍历出边时,点 \(3\) 可能先被遍历到了,然后才被点 \(2\) 遍历。
因此用 \(DJ\) 算法跑图论,有这样的一个性质:每个点可能入队多次,但只出队一次,且此时 \(dis[u]\) 已经被更新到了最优。这也是为什么要开一个vis
数组来标记是否访问,同时是这个算法的理论基础。
part2:关于堆优化
是否有一些精通重载运算符的大佬喜欢这样写?
struct node{
int id,d;
bool operator <(const node&a)const{
return dis[id]>dis[a.id];
}
};
void dijkstra(int st){
for(int i=1;i<=n;i++)
dis[i]=0x3f3f3f3f;
dis[st]=0;
priority_queue<node>q;
q.push((node){st,0});
while(q.size()){
int u=q.top().id;q.pop();
if(vis[u]) continue;vis[u]=1;
for(int e=head[u];e;e=edge[e].nex){
int v=edge[e].to;
if(dis[v]>dis[u]+edge[e].dis){
dis[v]=dis[u]+edge[e].dis;
q.push((node){v,dis[v]});
}
}
}
}
注意到结构体 \(node\) 的小于运算符有一些不同了。
这样会出什么问题吗?首先,我们来了解一下 STL priority_queue
。
其内置一个堆。
如图是一个优先队列中的小根堆(第一维为点,第二维为其入队时的 \(dis\),按第二维排序)。那么当我们像上面的代码一样写的话,\(dis\) 会被动态更新,而堆的结构却没有即使更新导致查询错误。
可供参考的代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
const int M = 5e5+5;
int head[N],dis[N],cnt[N];
struct Edge{
int nex,to,dis;
}edge[M];
struct node{
int id,d;
bool operator <(const node&a)const{
return d>a.d;
}
};
int n,m,s,elen;
bool vis[N];
void addedge(int from,int to,int dis){
edge[++elen]={head[from],to,dis};
head[from]=elen;
}
void dijkstra(int st){
for(int i=1;i<=n;i++)
dis[i]=0x3f3f3f3f;
dis[st]=0;
priority_queue<node>q;
q.push((node){st,0});
while(q.size()){
int u=q.top().id;q.pop();
if(vis[u])continue; vis[u]=1;
for(int e=head[u];e;e=edge[e].nex){
int v=edge[e].to;
if(dis[v]>dis[u]+edge[e].dis){
dis[v]=dis[u]+edge[e].dis;
q.push((node){v,dis[v]});
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1,u,v,w;i<=m;++i)
scanf("%d%d%d",&u,&v,&w),addedge(u,v,w);
dijkstra(s);
//for(int i=1;i<=n;++i)cout<<cnt[i]<<" ";
for(int i=1;i<=n;++i)
if(dis[i]!=0x3f3f3f3f)printf("%d ",dis[i]);
else printf("2147483647 ");
return 0;
}
最后鸣谢:lost_heart_hurts大佬为本文提供代码。
The End.
标签:node,DJ,int,vis,edge,Debug,id,dis 来源: https://www.cnblogs.com/keepcoder/p/15494876.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。