Dijkstra算法——计算一个点到其他所有点的最短路径的算法

迪杰斯特拉算法百度百科定义:传送门

gh大佬博客:传送门

迪杰斯特拉算法用来计算一个点到其他所有点的最短路径,是一种时间复杂度相对比较优秀的算法 O(n2)(相对于Floyd算法来说)

是一种单源最短路径算法,但是它并不能处理负边权的情况

Dijkstra的算法思想:①将一开始所有的非源点到源的距离设置成无限大(你认为的无限大实际上是0x3f(int)或者0x7fffffff(long long)),然后源到源距离设置成0(不就是0吗),然后每次找到一个距离源最短的点u,将其变成白点,枚举所有的蓝点,如果源到白点存在中转站——一个蓝点使得源->蓝点和蓝点->白点的距离和更短,就更新。②每找到一个白点,就尝试更新其他蓝点,直到更新完毕。

代码及注释:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-;
ll pp=;
ll mo(ll a,ll pp){if(a>= && a<pp)return a;a%=pp;if(a<)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=;for(;b;b>>=,a=mo(a*a,pp))if(b&)ans=mo(ans*a,pp);return ans;}
ll read(){
ll ans=;
char last=' ',ch=getchar();
while(ch<'' || ch>'')last=ch,ch=getchar();
while(ch>='' && ch<='')ans=ans*+ch-'',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}//快读
//head const int maxn=;
int g[maxn][maxn];//g数组用来存储图;
int n,m,s;//分别表示点的个数、有向边的个数、出发点的编号;
bool vis[maxn];//表示是否已经到达过;
int d[maxn];//d[i]表示从询问点到点i的最短路径;
const int inf=; int main ()
{
n=read(),m=read(),s=read();
rep(i,,n)
{
d[i]=inf; rep(j,,n)
g[i][j]=inf; g[i][i]=;//自己到自己的最短路径当然是0
}//初始化数组; rep(i,,m)
{
int u=read(),v=read(),w=read();
//u,v,i分别表示第i条有向边的出发点、目标点和长度;
g[u][v]=w;//读入;
} vis[s]=;//将起点标记成已经到达; rep(i,,n)
d[i]=g[s][i];//将最短路径初始化;
//如果两点之间有路线就初始化为该距离,如果没有就还是inf; while()
{
int stt_node=,stt_dis=inf;//stt=shortest 初始化两个变量
// stt_node表示最短路径的终点,stt_dis表示最短路径的长度 rep(i,,n)
{
if(vis[i]==&&d[i]<stt_dis)
//如果该点还没有到达,并且他的距离小于最短距离
{
stt_node=i,stt_dis=d[i];//更新变量
}
} if(stt_node==) break;
//如果已经没有可以更新的最短路径了,就说明已经结束了 vis[stt_node]=;//将该点标记成已经到达 rep(i,,n)
{
if(vis[i]||g[stt_node][i]==inf)continue;
//如果并没有到达或者是两点之间没有路径,就进入下一层循环 d[i]=min(d[i],stt_dis+g[stt_node][i]);//更新最短路径
}
} rep(i,,n)
printf("%d ",d[i]);
return ;
}

我们考虑一下对它的优化。因为如果我们每一次都要扫一遍判断出边,我们还不如直接存出边:

邻接表!(链式前向星)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-;
ll pp=;
ll mo(ll a,ll pp){if(a>= && a<pp)return a;a%=pp;if(a<)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=;for(;b;b>>=,a=mo(a*a,pp))if(b&)ans=mo(ans*a,pp);return ans;}
ll read(){
ll ans=;
char last=' ',ch=getchar();
while(ch<'' || ch>'')last=ch,ch=getchar();
while(ch>='' && ch<='')ans=ans*+ch-'',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}//快读
//head const ll INF = ;
struct edge
{
ll to, dis_, next;
} Edge[];
struct node
{
ll to, dis;
inline friend bool operator<(const node &a, const node &b)
{
return a.dis < b.dis;
}
};
ll head[], dis[];
bool vst[];
ll nodenum, edgenum, origin_node, cnt = , t;
priority_queue<node> q; inline void add_edge(ll from, ll to, ll value)
{
Edge[cnt].to = to;
Edge[cnt].dis_ = value;
Edge[cnt].next = head[from];
head[from] = cnt++;
} inline void dijkstra()
{
for (register int i = ; i < origin_node; i++)
{
dis[i] = INF;
}
//dis[origin_node]=0;
for (register int i = origin_node + ; i <= nodenum; i++)
{
dis[i] = INF;
}
q.push((node){origin_node, });
while (!q.empty())
{
int x = q.top().to;
q.pop();
if (vst[x])
continue;
vst[x] = ;
for (register int i = head[x]; i; i = Edge[i].next)
{
dis[Edge[i].to] = min(dis[Edge[i].to], dis[x] + Edge[i].dis_);
q.push((node){Edge[i].to, dis[Edge[i].to]});
}
}
} int main()
{
nodenum = read(), edgenum = read(), origin_node = read() ;//t=read();
for (register int i = ; i <= edgenum; i++)
{
register int f, t, v;
f = read(), t = read(), v = read();
add_edge(f, t, v);
}
dijkstra();
rep(i,,nodenum)
{
printf("%lld ",dis[i]);
} return ;
}
上一篇:【C语言】求旋转数组的最小数字,输入一个递增排序的数组的一个旋转,输出其最小元素


下一篇:MVC缓存02,使用数据层缓存,添加或修改时让缓存失效