迪杰斯特拉大家肯定不陌生,求单源最短路的基础算法。但这算法时间复杂度不尽人意,O(N^2)。所以大佬们就将它给优化了一下,可以达到O(Nlog(N))。那么怎么优化呢?首先我们来看看迪杰斯特拉是怎么求最短路的。这个算法是通过维护一个点集然后再贪心进行求解的。简单来说,就是我已知了n个点,这n个点在目前为止是我知道的可以从源点到达的点,当然它们的路径在目前来说是最优的,那我就通过遍历这些点,来扩展这个点集。朴素的迪杰斯特拉是用一个队列来维护这个点集。这里我们采用最小堆(优先队列)来维护这个点集,以此达到优化的目的。为什么可以这样优化?前面我们说过,迪杰斯特拉是对目前已知的源点可以到达的点进行扩展。假设点i被点now扩展了,那么dist[i]=dist[now]+map[now][i],那么我们何不从最小的dist[now]开始遍历,扩展呢?
我感觉我没讲清楚,但找不出其他描述了。也怪自己也没理解透就写博客了,不过真怕忘了又得在网上胡乱搜博客,还不如记录着,以后理解更深了再改或者自己变菜忘了再返回来翻开都方便。
下面上一个例题代码(洛谷3371 )
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m,s;
#define inf 2147483647
struct ha
{
int num;
long long val;
bool operator <(const ha &a) const
{
return val>a.val;
}
}node;
struct data
{
int to,next;
long long val;
}edge[500005];
int head[10005];
int cnt;
void addEdge(int s,int t,int v)
{
edge[cnt].to=t;
edge[cnt].val=v;
edge[cnt].next=head[s];
head[s]=cnt++;
}
void solve()
{
int vis[10005]={0};
long long dist[10005];
for(int i=1;i<=n;i++) dist[i]=inf;
dist[s]=0; vis[s]=0;
node.num=s; node.val=0;
priority_queue<ha> qu; qu.push(node);
while(!qu.empty())
{
ha no=qu.top();
int now = no.num;
qu.pop();
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i!=-1;i=edge[i].next)
{
int tto=edge[i].to;
if(!vis[tto]&&(dist[now]+edge[i].val<dist[tto]))
{
dist[tto]=edge[i].val+dist[now];
node.num=tto; node.val=dist[tto];
qu.push(node);
}
}
}
for(int i=1;i<n;i++)
printf("%lld ",dist[i]);
printf("%lld\n",dist[n]);
// return dist[n];
}
int main()
{
// while(scanf("%d%d",&n,&m) &&n&&m)
//{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&s);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
}
solve();
// }
return 0;
}