带有负权边最短路径问题

带有负权边的最短路径解法

前面写了一下Dijkstra算法求解单源最短路,但是该算法对于带有负权边时,是不适用的。下面来搞下其他的两种算法。Bellman-Ford算法,是一个无论思想上还是代码实现上都堪称完美的最短路算法。
核心代码只有4行

for(int k = 1; k <= n - 1; k ++)
for(int i = 1; i <= m; i ++)
if(dis[v[i]] > dis[u[i]] + w[i])
dis[v[i]] = dis[u[i]] + w[i];

完整代码如下:

#include<iostream>
#include<cstdio>
#define maxPath 99999999
using namespace std;
int n,m;
int u[1001],v[1001],w[1001],dis[1001];
int main()
{
   cin >> n >> m;
   //读入m条边 
   for(int i = 1; i <= m; i ++)
   cin >> u[i] >> v[i] >> w[i];
   //初始化dis 
   for(int i = 1; i <= n; i ++)
   dis[i] = maxPath;
   dis[1] = 0;
   
   for(int i = 1; i < n; i ++)
   for(int j = 1; j <= n; j ++)
   if(dis[v[j]] > dis[u[j]] + w[j])
    dis[v[j]] = dis[u[j]] + w[j];
    
    for(int i = 1; i <= n; i ++)
    cout << dis[i] << " ";
   return 0;
} 

要注意的是该算法可能不需要n-1松弛,可以在循环时放入check函数进行判断路径是否更新,若没有更新,则可以退出循环。

下面的一种算法是Bellman-Ford的队列优化算法。
先看下建立邻接表代码

for(int i = 1; i <=m; i ++)
{
 //读入每一条边
 scanf("%d%d%d",&u[i],&v[i],&w[i]);
 next[i]= first[u[i]];
 first[u[i]] = i;
}

next[i]里面存储的是u[i]节点为起点的上一条边的编号
first里面存储的是最新的一条边编号
该算法完整代码如下:

#include<iostream>
#include<cstdio>
#define maxPath 99999999
using namespace std;
int n,m;
int u[1001],v[1001],w[1001],dis[1001];
int book[1001];
int que[1001],head = 1,tail = 1;
int first[1001],next[1001];
int main()
{
   cin >> n >> m;
   for(int i = 1; i <= n; i ++)
   dis[i] = maxPath;
   dis[1] = 0;
   
   for(int i = 1; i <= n; i ++)
   first[i] = -1;
   for(int i = 1; i <= m; i ++)
   {
    scanf("%d%d%d",&u[i],&v[i],&w[i]);
    next[i] = first[u[i]];
    first[u[i]] = i;
   }
   que[head] = 1;
   tail ++;
   book[1] = 1;
   int k = 0;
   while(head < tail)
   {
    k = first[que[head]];
    while(k != -1)
    {
      if(dis[v[k]] > dis[u[k]] + w[k])
   {
    dis[v[k]] = dis[u[k]] + w[k];
    if(book[v[k]] == 0)
    {
      que[tail] = v[k];
     tail ++;
     book[v[k]] = 1; 
  }
   }
   k = next[k]; 
 }
 //book[que[head]] = 0;
 head ++;
   }
   for(int i = 1; i <= n; i ++)
   cout << dis[i] << " ";
   return 0;
} 

这也是队列的一种思想,想从源点开始找可以到达的点,再将路径更新,head++,重复此过程。

发布了26 篇原创文章 · 获赞 0 · 访问量 1357

猜你喜欢

转载自blog.csdn.net/weixin_43846217/article/details/104090226