图论 Dijkstra+堆优化
Posted dancer16
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图论 Dijkstra+堆优化相关的知识,希望对你有一定的参考价值。
dijkstra是一种单元最短路径算法,其能在较好时间复杂度内处理这一问题。但其对负权圈的处理让人不太满意——会陷入死循环
其思想和Prim算法差不多,都是贪心。
把图中的所有点划分为两个集合:包含远点S和不包含原点S的
每次从不包含原点S的集合中找出一个离原点S最近的点(这样就没有点能够比这个点更加接近原点,这也是其不能处理负权边的原因)
我们先考虑简单一点的情况:没有负权边
设u是不包含s中dist最小的那个点,另外v是不包含S中的任意点
如果v能更新u点<==>dist[v]+map[v][u]<dist[u];因为map[v][u]>0所以有dist[v]<dist[u]假设不成立
所以我们就有一个算法啦
1.每次找出不包含S中最近点,加入包含s的集合
2.维护所有和这个店相连的不在包含s的集合里的点到原点的距离(Prim维护的是到包含S的集合的距离)
时间复杂度Θ(n^2)比较优,适合稠密图。
但我们发现每次找一个最近点有点耗时,因为要支持减值和求最小的操作,就用优先队列啦
(优先队列在小根堆情况下支持降值,大根堆下支持升值)但优先队列里的元素有O(E)个开空间时需注意~~
上代码~
转自HK大神的blog,对于重载()不是很懂
#include<iostream> #include<cstdio> #include<queue> using namespace std; int n,m,S,tot,Next[500010],head[20000],tree[500010],val[500010]; bool visit[20000]; long long dis[20000]; struct cmp { bool operator()(int a,int b) { return dis[a]>dis[b]; } }; priority_queue<int,vector<int>,cmp> Q; void add(int x,int y,int z) { tot++; Next[tot]=head[x]; head[x]=tot; tree[tot]=y; val[tot]=z; } int main() { scanf("%d%d%d",&n,&m,&S); tot=0; for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); if (x==y) continue; add(x,y,z); } for (int i=1;i<=n;i++) { visit[i]=false; dis[i]=2147483647; } Q.push(S); dis[S]=0; while (!Q.empty()) { int u=Q.top(); Q.pop(); if (visit[u]) continue; visit[u]=true; for (int i=head[u];i;i=Next[i]) { int v=tree[i]; if (!visit[v]&&dis[v]>dis[u]+(long long)val[i]) { dis[v]=dis[u]+val[i]; Q.push(v); } } } for (int i=1;i<=n-1;i++) printf("%lld ",dis[i]); printf("%lld\n",dis[n]); return 0; }
以上是关于图论 Dijkstra+堆优化的主要内容,如果未能解决你的问题,请参考以下文章