关于SPFA它死了,它又复活了

· · 个人记录

一切的一切还是源自这道题:P3275 [SCOI2011] 糖果 - 洛谷

这道题本是可用 SPFA 过的,但是出题人加了一些卡 SPFA 的数据,因此 TLE 了。但是我在求助区看到了这位大佬的优化,我才明白:SPFA它又复活了

其实思路很简单。卡 SPFA 的数据是使用了特殊的建图方式,使图比较特殊。那么我们在建图时也可以随机建图。事实证明,非常有用。

根据大佬的思路,需要用随机种子 random_device,随机函数 mt19937,以及打乱容器顺序函数 shuffle。由于这道题要用最长路,自然应该让长度长的先进队列。

这是我的 P3275 的代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 5;
typedef long long ll;
struct edge{
    ll to, next, w;
}e[maxn << 1];
ll d[maxn], head[maxn], len, n, m, cnt[maxn];
bool vis[maxn];
deque<ll>q;
inline void Spfa(ll s){
    q.push_back(s);
    d[s] = 0;
    vis[s] = 1;
    while(!q.empty()){
        ll u = q.front();
        vis[u] = 0;
        q.pop_front();
        for(ll i = head[u]; i; i = e[i].next){
            ll v = e[i].to;
            if(d[v] < d[u] + e[i].w){
                d[v] = d[u] + e[i].w;
                cnt[v] = cnt[u] + 1;
                if(cnt[v] > n){
                    cout << "-1" << endl;
                    return;
                }
                if(!vis[v]){
                    vis[v] = 1;
                    if(!q.empty() && d[u] + e[i].w >= d[q.front()]) q.push_front(v);
                    else q.push_back(v);
                }
            }
        }
    }
    ll ans = 0;
    for(int i = 1; i <= n; ++i)
        ans += d[i];
    cout << ans << endl;
}
inline void insert(ll u, ll v, ll w){
    e[++len].to = v;
    e[len].w = w;
    e[len].next = head[u];
    head[u] = len;
}
inline void solve(){
    ios::sync_with_stdio(0);
    cin.tie(nullptr), cout.tie(nullptr);
    cin >> n >> m;
    ll beg = n + 1;
    for(ll i = 0; i <= beg; ++i)
        d[i] = -0x3f3f3f3f;
    for(ll i = 1; i <= m; ++i){
        ll a, b, c;
        cin >> c >> a >> b;
        if(c == 1)
            insert(a, b, 0), insert(b, a, 0);
        else if(c == 2)
            insert(a, b, 1);
        else if(c == 3)
            insert(b, a, 0);
        else if(c == 4)
            insert(b, a, 1);
        else
            insert(a, b, 0);
        if(a == b && (c == 2 || c == 4)){
            printf("-1\n");
            return;
        }
    }
    vector<ll>nice;
    for(ll i = 1; i <= n; ++i)
        nice.push_back(i);
    random_device send; //制造一个随机种子
    mt19937 f(send()); //根据随机种子建立随机函数
    shuffle(nice.begin(), nice.end(), f); //打乱容器
    for(auto i : nice) //随机化建图
        insert(0, i, 1);
    Spfa(0);
}
int main(){
    solve();
    return 0;
}