SPFA的两种优化(SLF+LLL)

d[i]:i到达起始节点的目前最小值。

q:deque,双端队列。

sum:队列中元素和。

SLF:Small Label First 策略,设要加入的节点是j,若d[j]<d[q.front()],则将j插入队首,否则插入队尾

 LLL:Large Label Last 策略,设队首元素为i,队列中所有d值的平均值为x,若d[i] * (int)q.size() <= sum,则将i插入到队首(注意,d[i]的值可能相比之前计算到sum时已经发生改变,更新了,但是更新只会使得d[i]变小(因为只有比之前小才会发生改变),我们知道插入队首的条件为d[i] * (int)q.size() <= sum,当d[i]小了,如果原来使得插入队首的条件满足,那么现在比之前小也能满足条件),否则,则插入队尾并且查找下一元素,直到找到某一i使得d[i] * (int)q.size() > sum,则将i出队进行松弛操作。(为什么q.size()要强制转换成int类型,这是因为在C标准中当int类型*unsigned类型时,结果为unsigned类型,且d[i]会先转换成unsigned类型与q.size()进行相乘,这样-1转换成unsigned类型的值就为unsigned类型最大值,不是-1,所以可能造成程序无限循环)。

代码:

const int INF = 0x3fffffff;
struct Node{
    int to;
    int value;
    Node (int x, int y){
        to = x;
        value = y;
    } 
};
vector<Node> v[505];//邻接表对于v[i]连结的节点和权值(to是节点,value权值)
int d[505];//d[i]表示i到起始节点的距离
bool is_que[505];//是否在队列中
int cnt[505];//进队列的次数
bool spfa(int i, int n)//i起始节点,n节点数
{
    memset(cnt, 0, sizeof(cnt));
    memset(is_que, 0, sizeof(is_que));
    fill(d, d + 505, INF);
    d[i] = 0;
    cnt[i] = 1;
    deque<int> q;
    is_que[i] = true;
    q.push_back(i);
    int sum = d[i];
    while(!q.empty())
    {
        int t = q.front();
        while(d[t] * (int)q.size() > sum)//SLF策略
        {
            int p = q.size();
            q.push_back(t);
            q.pop_front();
            t = q.front();
        }
        q.pop_front();
        sum -= d[t];//记得出了队列剪除原来的值
        is_que[t] = false;
        for(int j = 0; j < v[t].size(); j++)
        {
            if(v[t][j].value + d[t] < d[v[t][j].to])
            {
                d[v[t][j].to] = v[t][j].value + d[t];
                if(!is_que[v[t][j].to])
                {
                    is_que[v[t][j].to] = true;
                    if(!q.empty() && d[v[t][j].to] >= d[q.front()])//LLL策略
                        q.push_back(v[t][j].to);
                    else
                        q.push_front(v[t][j].to);
                    sum += d[v[t][j].to];
                    if(++cnt[v[t][j].to] > n)        
                        return false;
                }
            }
        }
    }
    return true;
}

 

posted @ 2020-02-05 20:09  funforever  阅读(261)  评论(0编辑  收藏  举报