spfa优化

s p f a spfa spfa 的优化都是基于 d e q u e deque deque 的,我们通常使用 L L L LLL LLL 优化,代码简单,优化效果最好,详情可见参考这里,例题可以参考这里

1. L L L LLL LLL 优化(入队优化)

Large Label Last 优化:思路就是将 d i s t dist dist 更大的点放入队尾,将 d i s t dist dist 更小的点放入队头,优先使用 d i s t dist dist 更小的点进行松弛操作。

void spfa(int head)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, false, sizeof st);
    dist[head] = 0;
    
    deque<int> q;
    q.push_front(head);
    st[head] = true;
    
    while(q.size())
    {
        int cur = q.front();
        q.pop_front();
        st[cur] = false;
        for(int i = h[cur]; i != -1; i = ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[cur] + w[i])
            {
                dist[j] = dist[cur] + w[i];
                if(!st[j])
                {
                /*============== LLL 优化 ==============*/
                    if(q.empty() || dist[j] > dist[q.front()])
                        q.push_back(j);
                    else    q.push_front(j);
                /*======================================*/
                    st[j] = true;
                }
            }
        }
    }
}

2. S L F SLF SLF 优化(出队优化)

Small Label First 优化:优先让 d i s t dist dist 更小的节点出队来进行松弛操作,不过这个“小”并不好把握,总不能遍历一遍队列找这个小的 d i s t dist dist 把。因此,这里的“小”是平均意义上的小,即小于等于队列中所有元素的平均值,因此我们要维护队列元素个数 c n t cnt cnt (不用q.size(),调用函数可能更慢)和队列中的元素和 s u m sum sum,通过 while 来进行判断,不过由于优化逻辑中有个 while,其优化效果可能很玄?

void spfa(int head)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, false, sizeof st);
    dist[head] = 0;
    
    deque<int> q;
    q.push_front(head);
    st[head] = true;
    
    /*================================*/
    int sum = dist[head], cnt = 1;
    /*================================*/
    
    while(q.size())
    {
        int cur = q.front();
        /*============================*/
        while(dist[cur] * cnt > sum) 
        {
            q.push_front();
            q.push_back(cur);
            cur = q.front();
        }
        /*============================*/
        q.pop_front();
        st[cur] = false;
        /*============================*/
        cnt -- , sum -= dist[cur];
        /*============================*/
        for(int i = h[cur]; i != -1; i = ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[cur] + w[i])
            {
                dist[j] = dist[cur] + w[i];
                if(!st[j])
                {
                    q.push_back(j);
                    /*============================*/
                    cnt ++ , sum += dist[j]; 
                    /*============================*/
                    st[j] = true;
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值