codeforces1472G Moving to the Capital(spfa变形)

传送门
题解:首先看清题意后,发现这道题和cf1473E挺像的,首先算出 d d d 值,跑个 b f s bfs bfs ,然后接着考虑 a n s [ i ] [ 0 / 1 ] ans[i][0/1] ans[i][0/1] 表示起点为 i i i 的路径中其中没有 2 2 2 操作和有 1 1 1 2 2 2 操作的路径中所能到达的最小的 d d d 值,所以更新其实还是简单的。考虑一条边为 i − > j i->j i>j,那么
i f ( d [ i ] < d [ j ] )   a n s [ i ] [ 0 ] = m i n ( a n s [ i ] [ 0 ] , a n s [ j ] [ 0 ] ) , a n s [ i ] [ 1 ] = m i n ( a n s [ i ] [ 1 ] , a n s [ j ] [ 1 ] ) e l s e   a n s [ i ] [ 1 ] = m i n ( a n s [ i ] [ 1 ] , a n s [ j ] [ 0 ] ) if(d[i]<d[j])\ ans[i][0]=min(ans[i][0],ans[j][0]),ans[i][1]=min(ans[i][1],ans[j][1])\\ else\ ans[i][1]=min(ans[i][1],ans[j][0])\\ if(d[i]<d[j]) ans[i][0]=min(ans[i][0],ans[j][0]),ans[i][1]=min(ans[i][1],ans[j][1])else ans[i][1]=min(ans[i][1],ans[j][0])
然后考虑建反图,之后把初值全部压进 s e t set set 中,然后开始不断地 s p f a spfa spfa 直到没有更新。
代码中 a n s [ i ] [ 0 ] ans[i][0] ans[i][0] 表示为 d [ i ] . f i r s t d[i].first d[i].first a n s [ i ] [ 1 ] ans[i][1] ans[i][1] 表示为 d [ i ] . s e c o n d d[i].second d[i].second .

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int main()
{
    int T;
    cin >> T;
    while (T--) {
        int n, m;
        cin >> n >> m;
        vector<int> g[n], rg[n];
        for (int i = 0, u, v; i < m; i++) {
            cin >> u >> v;
            u--; v--;
            g[u].emplace_back(v);
            rg[v].emplace_back(u);
        }
        vector<int> dis(n);
        vector<pair<int, int>> d(n, {inf, inf});
        queue<pair<int, int>> q;
        d[0].first = 0;
        dis[0] = 0;
        set<pair<int, pair<int, int>>> s;
        q.push({0, 0});
        s.insert({0, {0, 0}});
        while (!q.empty()) {
            int u = q.front().first, w = q.front().second;
            q.pop();
            for (auto x : g[u]) {
                if (x == 0 || d[x].first != inf) {
                    continue;
                } else {
                    d[x].first = w + 1;
                    dis[x] = d[x].first;
                    q.push({x, d[x].first});
                    s.insert({d[x].first, {x, 0}});
                }
            }
        }
        while (!s.empty()) {
            auto [u, f] = s.begin()->second;
            s.erase(s.begin());
            for (auto v : rg[u]) {
                if (f == 0) {
                    if (dis[v] < dis[u]) {
                        if (d[v].first > d[u].first) {
                            auto it = s.find({d[v].first, {v, 0}});
                            if (it != s.end()){
                                s.erase(it);
                            }
                            d[v].first = d[u].first;
                            s.insert({d[v].first, {v, 0}});
                        }
                    }else {
                        if (d[v].second > d[u].first) {
                            auto it = s.find({d[v].second, {v, 1}});
                            if (it != s.end()){
                                s.erase(it);
                            }
                            d[v].second = d[u].first;
                            s.insert({d[v].second, {v, 1}});
                        }
                    }
                } else {
                    if (dis[v] < dis[u]) {
                        if (d[v].second > d[u].second) {
                            auto it = s.find({d[v].second, {v, 1}});
                            if (it != s.end()){
                                s.erase(it);
                            }
                            d[v].second = d[u].second;
                            s.insert({d[v].second, {v, 1}});
                        }
                    }
                }
            }
        }
        for (auto x : d) {
            cout << min(x.first, x.second) << " ";
        }
        cout << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值