SPFA算法优化—SLF和LLL优化

版权声明:看我干嘛? 你又没打算转载我的博客~ https://blog.csdn.net/wjh2622075127/article/details/82532919

SPFA算法有两个小优化,虽然效率提升不多,但还是有的。

如下四张图分别是朴素SPFA、SLF优化、LLL优化、SLF+LLL优化的在洛谷P1359租用游艇上的耗时情况。

SPFA
SLF
LLL
SLF+LLL

可以看到差别还是有的。

一、SLF(Small Label First)优化。

他的思路很简单:原队列改为双端队列,对一个要加入队列的点u,如果dis[u] 小于队首元素v的dis[v],那么就就加入到队首元素,否则加入到队尾。

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 205;
int n, dis[maxn];
int G[maxn][maxn] = {};
bool inq[maxn] = {};

int main()
{
    memset(dis, 0x3f, sizeof(dis));
    cin >> n;
    for (int i = 1; i < n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            cin >> G[i][j];
        }
    }
    deque<int> Q;
    Q.push_back(1);
    inq[1] = true;
    dis[1] = 0;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop_front();
        inq[u] = false;
        for (int i = u + 1; i <= n; ++i) {
            if (dis[i] > dis[u] + G[u][i]) {
                dis[i] = dis[u] + G[u][i];
                if (!inq[i]) {
                    if (dis[i] <= dis[Q.front()]) Q.push_front(i);
                    else Q.push_back(i);
                    inq[i] = true;
                }
            }
        }
    }
    cout << dis[n];
}

二、LLL(Large Label Last)优化

它的策略是:对每个要出对的元素u,比较dis[u]和队列中dis的平均值,如果dis[u]更大,那么将它弹出放到队尾,取队首元素在进行重复判断,直至存在dis[x]小于平均值

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 205;
int n, dis[maxn], sum = 0, cnt = 0;
int G[maxn][maxn] = {};
bool inq[maxn] = {};

int main()
{
    memset(dis, 0x3f, sizeof(dis));
    cin >> n;
    for (int i = 1; i < n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            cin >> G[i][j];
        }
    }
    queue<int> Q;
    Q.push(1);
    inq[1] = true;
    dis[1] = 0;
    cnt = 1;
    while (!Q.empty()) {
        int u = Q.front();
        while (dis[u]*cnt > sum) {
            Q.pop();
            Q.push(u);
            u = Q.front();
        }
        Q.pop();
        cnt--;
        sum -= dis[u];
        inq[u] = false;
        for (int i = u + 1; i <= n; ++i) {
            if (dis[i] > dis[u] + G[u][i]) {
                dis[i] = dis[u] + G[u][i];
                if (!inq[i]) {
                    Q.push(i);
                    sum += dis[i];
                    cnt++;
                }
            }
        }
    }
    cout << dis[n];
}

三、SLF + LLL同时优化版

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

const int maxn = 205;
int n, dis[maxn], sum = 0, cnt = 0;
int G[maxn][maxn] = {};
bool inq[maxn] = {};

int main()
{
    memset(dis, 0x3f, sizeof(dis));
    cin >> n;
    for (int i = 1; i < n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            cin >> G[i][j];
        }
    }
    deque<int> Q;
    Q.push_back(1);
    inq[1] = true;
    dis[1] = 0;
    cnt = 1;
    while (!Q.empty()) {
        int u = Q.front();
        while (cnt*dis[u] > sum) {
            Q.pop_back();
            Q.push_back(u);
            u = Q.front();
        }
        Q.pop_front();
        cnt--;
        sum -= dis[u];
        inq[u] = false;
        for (int i = u + 1; i <= n; ++i) {
            if (dis[i] > dis[u] + G[u][i]) {
                dis[i] = dis[u] + G[u][i];
                if (!inq[i]) {
                    if (dis[i] <= dis[Q.front()]) Q.push_front(i);
                    else Q.push_back(i);
                    inq[i] = true;
                    sum += dis[i];
                    cnt++;
                }
            }
        }
    }
    cout << dis[n];
}

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/82532919