最短路算法

1.Dijkstra算法

算法思想:dijkstra 算法采用的是贪心的思想。

(1)定义一个dis数组,dis[i] 表示i点到源点的最短路径,设源点的 dis 值为0,其他 dis 值为
(2)选出其中的最小 dis 值,进行标记并更新它相邻的 dis 值。

(3)不断循环操作(2)。

优点:dijkstra 算法可以广泛使用于大多数题目。

缺点: dijkstra 算法不能在图中有负权环时使用。

核心代码:

void dijkstra()
{
for(int i=1;i<=n;i++)d[i]=INF;
dis[1]=0;
for(int i=1;i<=n;i++)
{
int mark=-1;
mindis=INF;
for(int k=1;k<=n;k++)
{
for(int j=head[i];j;j=edge[j].nxt)
{
if(!vis[edge[j].to]&&edge[j].dis<mindis)
{
mindis=edge[j].dis;
mark=edge[j].to;
}
}
}
vis[mark]=1;
for(int i=head[mark];i;i=edge[i].nxt)
{
if(!vis[edge[i].to])
{
d[edge[i].to]=min(d[edge[i].to],d[mark]+edge[i].dis);
}
}
}
}

堆优化:

struct node{
int dis,pos;
bool operator<(const node &x) const
{
return x.dis<dis;
}
};
inline void dij(int s)
{
for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f3f3f3f3f, vis[i]=0;
priority_queue<node> q;
dis[s]=0, q.push((node){0, s});
while(q.size())
{
int u=q.top().pos;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=edge[i].w+dis[u];
q.push((node){dis[v], v});
}
}
}
}

2. Bellmax-ford算法

(1) 定义一个 dis 数组,dis[i] 表示 i 点到源点的最短路径,设源点的 dis 值为0,其他 dis 值为

(2) 从图的任意边开始,对每一条边进行松弛操作(对于边 u>v ,如果 dis[v]>dis[u]+w[u][v],dis[v]=dis[u]+w[u][v] , w 为图的权值)①,重复点数-1次。

(3)最后再进行一边松弛操作,如果存在①,则存在负权环。

优点:Bellman-ford算法边的权值可以为负数,并可检测负权回路。

缺点:时间复杂度过高。

核心代码:

bool bellman(int v0)
{
for(int i=1;i<=nv-1;i++)
{
for(int j=1;j<=ne;j++)
{
if(dis[edge[j].a]+edge[j].w<dis[edge[j].b])
{
dis[edge[j].b]=dis[edge[j].a]+edge[j].w;
}
}
for(int j=1;j<=ne;j++)
{
if(d[edge[j].a]+edge[j].w<dis[edge[j].b])
{
return 0;
}
}
return 1;
}
}

3. SPFA算法:

算法思想:SPFA算法实际是Bellmanford算法的队列优化。

(1) 定义一个dis数组,dis[i] 表示i点到源点的最短路径,设源点的 dis 值为0,其他 dis 值为 。定义队列 q ,源点进队。

(2) 从队列中取出队首元素 u,标记节点 u 出队,对u相连的所有节点 v 进行松弛操作。如果松弛成功,检查节点 v 进队次数,如果超过 |V|,则说明出现负权环,算法结束;否则,修改 dis[v] ,检查节点 v 是否在队列中,如果不在,节点 v 进队。

(3) 重复操作(2)。

优点:可以解决负权环问题。

核心代码:

void spfa(int u)
{
queue<int> q;
q.push(u), dis[u]=0, vis[u]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].first;
if(dis[v]>dis[u]+edge[i].w||dis[v]<0)
{
dis[v]=dis[u]+edge[i].w;
}
if(vis[v]==1)
{
vis[v]=1;
q.push(v);
}
}
}
}

4. Floyd算法

算法思想:Floyd算法是基于动态规划思想的。

(1) 定义 dp[k][i][j] 表示从点i到点j只允许经过前k个点得到的最短路径。

(2) 如果经过第k个点,那么 dp[k][i][j]=dp[k1][i][k]+dp[k1][k][j]

(3) 如果经过第k个点,那么 dp[k][i][j]=dp[k1][i][j]

(4) dp[k][i][j]=min(dp[k1][i][j],dp[k1][i][k]+dp[k1][k][j])

(5) 边界:dp[0][i][j]=g[i][j],g[i][j]ij的边权,当无法到达时可以设为

优点:稠密图效果佳,边权可为负。

核心代码:

memset(dis, 0x7f, sizeof(dis));
for(int i=1;i<=m;i++)
{
int u, v;
cin>>u>>v;
dis[u][v]=dis[v][u]=w[u][v];
}
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i!=j)&&(i!=k)&&(j!=k))
{
if(dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
}
}
}
}
}

our story begins.

posted @   zhouyiran2011  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示