版权声明:看我干嘛? 你又没打算转载我的博客~ https://blog.csdn.net/wjh2622075127/article/details/82532919
SPFA算法有两个小优化,虽然效率提升不多,但还是有的。
如下四张图分别是朴素SPFA、SLF优化、LLL优化、SLF+LLL优化的在洛谷P1359租用游艇上的耗时情况。
可以看到差别还是有的。
一、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];
}