Bellman-Ford算法(BF)与SPFA算法

BF

Dijkstra算法可以很好的解决无负权图,但如果出现了负权边,便会失效。
首先,图的任意一条最短路径既不能包含负权回路,也不会包含正权回路,因此它最多包含|v|-1条边。,如果把源点S作为一棵树的根结点,把其他结点按照最短路径的结点顺序连接,就会生成一棵最短路径树。
主要思路如下(伪代码)复杂度为(V*E):

for(i=0;i<n-1;i++)//n为顶点数
    {
        for(each edge u->v)//每轮操作遍历所有边
        {
            if(d[u]+length[u->v]<d[v])//以u为中介点可以使的d[v]更小
            {
                d[v]=d[u]+length[u->v];//松弛操作
            }
        }
    }

邻接表的代码:

struct node
{
    int v,dis; //v为邻接边的目标定点,dis为邻接边的边权
};

vector<node> aj[maxx];
int n;
int d[maxx]; //起点到达各点的最短路径长度

bool bellman(int s) //s为源点
{
    fill(d,d+maxx,INF);
    d[s]=0; 
    for(int i=0;i<n-1;i++)
        for(int u=0;u<n;u++)
            for(int j=0;j<aj[u].size();u++)
            {
                int v=aj[u][j].v;//邻接边的顶点
                int dis=aj[u][j].dis;//邻接边的边权
                if(d[u]+dis<d[v])   //以u为中介点使d[v]更小
                    d[v]=d[u]+dis; //松弛
            }
    
    //判断负权的代码
    for(int u=0;u<n;u++)
        for(int j=0;j<aj[u].size();j++)
        {
            int v=aj[u][j].v;
            int dis=aj[u][j].dis;
            if(d[u]+dis<d[v]) //如果仍然可以被松弛
            {
                return false; //有负环
            }
        
        }
    
    return true}

SPFA

Bellman-Ford算法时间复杂度过高,优化后被称为SPFA算法。
代码思路如下:

struct node
{
    int v,dis; //v为邻接边的目标定点,dis为邻接边的边权
};

vector<node> aj[maxx];
int n;
int d[maxx]; //起点到达各点的最短路径长度
bool inq[maxx]; //顶点是否在队列中

bool SPFA(int s)
{
    memset(inq,false,sizeof(inq));
    memset(num,0,sizeof(num));
    fill(d,d+maxx,INF);
    queue<int> q;
    q.push(s); //源点入队
    inq[s]=true; //原点已入队
    num[s]++; //入队次数加1
    d[s]=0;  
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=false;
        for(int j=0;j<aj[u].size();j++)
        {
            int v=aj[u][j].v;
            int dis=aj[u][j].dis;
            if(d[u]+dis<d[v])
            {
                d[v]=d[u]+dis;
                if(!inq[v])//如果v不在队列中
                {
                    q.push(v);
                    inq[v]=true;
                    num[v]++;
                    if(num[v]>=n)//超过了n
                        return false; //有可达负环
                }
            }
        }
    }
    return true;
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值