SPFA的两种实现形式(二维数组与数组模拟邻接表)

输入描述

第一行有两个数n,m表示有n个点m条边

第2~m+1行有三个数a,b,c表示a点与b点间的距离

第m+2行有两个数x,y表示询问x点到y点的最短路

输出描述

一个数ans,表示x点到y点的最短路长度

【样例输入】          
        5  7
        1  3  7
        2  4  6
        1  2  2
        2  5  3
        1  4  8
        3  5  1
        5  4  6
        1  3
 
  【样例输出
        6

如图所示:

1.二维数组实现

#include<algorithm>

#include<iostream>

#include<cstring>

#include<cstdio>

#include<queue>

using namespace std;

const int INF = 1000;
int n,m,x,y,dist[INF];  //x,y分别为起点和终点,n,m分别为点数与边数,dist存放结果;
int dis[INF][INF],w[INF][INF];  
//dis用来存储边权;w[i,0]存储与i有关联的点的个数;w[i,j]存储与i关联的各个点
bool used[INF];
 //用来判断是否在队列中

int main()
{
        memset(dist,127/3,sizeof(dist));
memset(used,false,sizeof(used));
memset(dis,127/3,sizeof(dis));
        scanf("%d %d", &n, &m);
int a,b,c;
for ( int i = 1 ; i <= m ; i++ )

{

                scanf("%d %d %d", &a, &b, &c);

w[a][0]++ ; w[a][w[a][0]] = b ; dis[a][b] = c ;
w[b][0]++ ; w[b][w[b][0]] = a ; dis[b][a] = c ;
        }  
        scanf("%d %d", &x, &y);
        queue<int> p;
dist[x] = 0;
p.push(x);used[x] = true;
while (!p.empty())
{
int now = p.front();
for ( int i = 1 ; i <= w[now][0] ; i ++ )

{

  //逐点松弛,如果不在队列中则加入队列

if ( dist[w[now][i]] > dist[now] + dis[now][w[now][i]] )
{
dist[w[now][i]] = dist[now] + dis[now][w[now][i]];
if ( !used[w[now][i]] )
{
p.push(w[now][i]);
used[w[now][i]] = true;
}

}
p.pop();
used[now] = false;
}
printf("%d", dist[y]);
return 0;

}


2.数组模拟邻接表实现//表现为存储空间上的优越性

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
 
using namespace std;
 
const int INF = 1000001;
const int end = -1;
int f[INF],dist[INF],n,m,x,y,a,b,c,d = 0;//假设最多不超过INF个点
bool used[INF]; 
struct q{
 int ans,next,link;
}s[INF];//假设最多不超过INF条边
 
void add(int a, int b, int c)
{
//用s.link存储该点指向的一个点
//s.ans存储边长
/*s.next存储上一个该点指向的点在数组s中的位置(在下面的松弛过程中如果结果是-1,就说明该点所连接的点已经全部松弛过了)*/

 d++;
 s[d].ans = c;
 s[d].link = b;
 s[d].next = f[a];
 f[a] = d; //记录这一路线(两点加一边)在数组s中的位置
}
 
int spfa(int a,int b)
{
//原理同二维数组写法的原理,只是把w数组的作用用邻接表代替了
 queue<int> p;
 memset(dist,127,sizeof(dist));
    dist[a] = 0 ;
    p.push(a);used[a] = true;
    while(!p.empty())
    {
     int now = p.front();
     for (int i = f[now] ; i != -1 ; i = s[i].next )
//根据链逐点松弛,作用同二维数组写法里的w数组
     {
      if ( dist[s[i].link] > s[i].ans+dist[now] )
      {
       dist[s[i].link] = s[i].ans+dist[now];
       if (!used[s[i].link])
    {
        p.push(s[i].link);
           used[s[i].link] = true;
          }
      }
     }
     p.pop();
     used[now] = false;
    }
    return dist[b];
}
 
int main()
{
 scanf("%d %d", &n, &m);
 memset(f,end,sizeof(f));
 memset(used,false,sizeof(used));
 for (int i = 1 ; i <= m ; i++)
 {
  scanf("%d %d %d\n", &a , &b, &c);
  add(a,b,c);
  add(b,a,c);
 }
 scanf("%d %d", &x, &y);
 int ans = spfa(x,y);
 printf("%d", ans);
 return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值