前言
本文所有内容出自于个人的理解,可能有谬误,还请多多包涵,敬请指正。qq :2039316792
本文中参考的所有文章,将会在专页中一一列出。
目录
正文
1、Dijkstra
概论
Dijkstra算法是一种单源最短路算法,适用于无负权的图。其采用了BFS+贪心的方式来更新最短路。
基本流程
- 初始化dis[每一个点]= ∞,dis[起点]=0。
- 标记起点,加入集合S。其他点不标记,加入集合U。
- 从集合U中选取与当前点A距离最近的点B。
- 若起点到点A的距离+点A到点B的距离小于dis[]中存贮的值,则执行语句4,否则若起点到点A的距离+点A到点B的距离小于dis[]中存贮的值,则更新dis和当前点。
- 若所有的点都已经被标记过,则算法结束,否则,重复执行语句3。
PS :由于时间原因,不在此加图,以后我会更新一个GIF来更好得描述次过程。
时间复杂度
-
朴素算法: O( n² )
-
heap :
- 小根堆(优先队列) O( (n+m)logn )
- 斐波那契堆 O( m+nlogn )
代码实现
PS:以下代码以洛谷 P3371 【模板】单源最短路径(弱化版)为例
#include<bits/stdc++.h>
#define maxn 10005
#define inf 2147483647
using namespace std;
int n,m,s,minn,s,cnt;
int dis[maxn],head[maxn];
bool vis[maxn];
struct edge
{
int nxt,to,w;
}h[500005];
void add(int u,int v,int w)
{
h[++cnt].next=head[u];
h[tot].to=v;
h[tot].w=w;
head[u]=cnt;
}
inline void dij()
{
for(int i=1;i<=n;i++)dis[i]=inf;
dis[s]=0;
for(int i=1;i<=n;i++)
{
minn=inf;t=-1;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<minn)
{
minn=dis[j];
t=j;
}
}
if(t==-1)break;
vis[t]=1;
for(int j=head[t];j;j=h[j].next)
{
if(!vis[h[j].to]&&dis[h[j].to]>(h[j].w+dis[t]))
dis[h[j].to]=h[j].w+dis[t];
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
int u,v,w;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dij();
for(int i=1;i<=n;i++)
printf("%d",dis[i]);
return 0;
}
优化
在上述代码中,我们用枚举的方式来找到与当前节点相连的非来源边的边的最小值,这里显然是十分浪费时间的,作为追求时间效率oiers,我们对这里用堆来优化。
一般而言,oiers还会追求代码的简洁,所以,我们用stl中的priority_queue来模拟堆。
PS:以下代码以洛谷 P3371 【模板】单源最短路径(标准版)为例
#include <bits/stdc++.h>
#define inf 1e9f
#define ll long long
#define maxn 200100
using namespace std;
struct node
{
ll val,id;
bool operator <(const node &x) const
{
return val>x.val;
}
};
priority_queue<node> q;
vector< pair<ll,ll> >a[maxn];
ll n,m,s,dis[maxn];
bool vis[maxn];
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
ll u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
a[u].push_back(make_pair(v,w));
}
for(int i=1;i<=n;i++)dis[i]=inf;
dis[s]=0;
q.push((node){0,s});
while(!q.empty())
{
ll p=q.top().id;
q.pop();
if(vis[p])continue;
vis[p]=true;
for(int i=0;i<a[p].size();i++)
{
int to=a[p][i].first,val=a[p][i].second;
if(!vis[to]&&dis[p]+val<dis[to])
{
dis[to]=dis[p]+val;
q.push((node){dis[to],to});
}
}
}
for(int i=1;i<=n;i++) printf("%lld ",dis[i]);
return 0;
}
2、Spfa
3、floyd
参考文献
福利
就不更╭(╯^╰)╮