codeforces1473E Minimum Path(spfa变形)

传送门
如果只求第 1 1 1个点分别到第 i i i个点的最小值,那么直接跑个 d i j dij dij,但是本题加了路径上分别要减去最大值和加上最小值,那么考虑 d [ i ] [ 0 / 1 ] [ 0 / 1 ] d[i][0/1][0/1] d[i][0/1][0/1]分别表示为从第 1 1 1个点到第 i i i个点没减去最大值/已经减去最大值和没减去最小值/已经减去最小值的最小路径,那么最后答案必然是各个 d [ i ] [ 1 ] [ 1 ] d[i][1][1] d[i][1][1],最后分析一波
d [ v ] [ 0 ] [ 0 ] = m i n ( d [ u ] [ 0 ] [ 0 ] + w , d [ v ] [ 0 ] [ 0 ] ) d [ v ] [ 1 ] [ 0 ] = m i n ( d [ u ] [ 0 ] [ 0 ] , d [ v ] [ 1 ] [ 0 ] ) d [ v ] [ 1 ] [ 0 ] = m i n ( d [ u ] [ 1 ] [ 0 ] + w , d [ v ] [ 1 ] [ 0 ] d [ v ] [ 0 ] [ 1 ] = m i n ( d [ u ] [ 0 ] [ 0 ] + 2 ∗ w , d [ v ] [ 0 ] [ 1 ] ) d [ v ] [ 0 ] [ 1 ] = m i n ( d [ u ] [ 0 ] [ 1 ] + w , d [ v ] [ 0 ] [ 1 ] ) d [ v ] [ 1 ] [ 1 ] = m i n ( d [ u ] [ 0 ] [ 0 ] + w , d [ v ] [ 1 ] [ 1 ] ) d [ v ] [ 1 ] [ 1 ] = m i n ( d [ u ] [ 1 ] [ 0 ] + 2 ∗ w , d [ v ] [ 1 ] [ 1 ] ) d [ v ] [ 1 ] [ 1 ] = m i n ( d [ u ] [ 0 ] [ 1 ] , d [ 1 ] [ 1 ] [ 1 ] ) d [ v ] [ 1 ] [ 1 ] = m i n ( d [ u ] [ 1 ] [ 1 ] + w , d [ v ] [ 1 ] [ 1 ] ) d[v][0][0]=min(d[u][0][0]+w,d[v][0][0])\\ d[v][1][0]=min(d[u][0][0],d[v][1][0])\\ d[v][1][0]=min(d[u][1][0]+w,d[v][1][0]\\ d[v][0][1]=min(d[u][0][0]+2*w,d[v][0][1])\\ d[v][0][1]=min(d[u][0][1]+w,d[v][0][1])\\ d[v][1][1]=min(d[u][0][0]+w,d[v][1][1])\\ d[v][1][1]=min(d[u][1][0]+2*w,d[v][1][1])\\ d[v][1][1]=min(d[u][0][1],d[1][1][1])\\ d[v][1][1]=min(d[u][1][1]+w,d[v][1][1]) d[v][0][0]=min(d[u][0][0]+w,d[v][0][0])d[v][1][0]=min(d[u][0][0],d[v][1][0])d[v][1][0]=min(d[u][1][0]+w,d[v][1][0]d[v][0][1]=min(d[u][0][0]+2w,d[v][0][1])d[v][0][1]=min(d[u][0][1]+w,d[v][0][1])d[v][1][1]=min(d[u][0][0]+w,d[v][1][1])d[v][1][1]=min(d[u][1][0]+2w,d[v][1][1])d[v][1][1]=min(d[u][0][1],d[1][1][1])d[v][1][1]=min(d[u][1][1]+w,d[v][1][1])
然后就是不断地跑spfa更新即可(参考官方题解)

准备改改代码规范了,该空格就得空格呢,毕竟代码是给别人看的

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, u, v, w;
long long d[N][2][2];
vector<pair<int, int>> g[N];
int main()
{
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        cin >> u >> v >> w;
        u--; v--;
        g[u].emplace_back(v, w);
        g[v].emplace_back(u, w);
    }
    for (int i = 0; i < n; i++) {
        for(int j = 0; j < 2; j++) {
            for(int k = 0; k < 2; k++) {
                d[i][j][k] = (long long)1e18;
            }
        }
    }
    d[0][0][0] = 0;
    set<pair<long long, array<int, 3>>> q;
    q.insert({0, {0, 0, 0}});
    while (!q.empty()) {
        auto [u, mx, mn] = q.begin()->second;
        q.erase(q.begin());
        for (auto [v, w] : g[u]) {
            for (int i = 0; i <= 1 - mx; i++) {
                for (int j = 0; j <= 1 - mn; j++) {
                    if (d[v][i | mx][j | mn] > d[u][mx][mn] + (1 - i + j) * w) {
                        auto it = q.find({d[v][i | mx][j | mn], {v, i | mx, j | mn}});
                        if (it != q.end()) {
                            q.erase(it);
                        }
                        d[v][i | mx][j | mn] = d[u][mx][mn] + (1 - i + j) * w;
                        q.insert({d[v][i | mx][j | mn], {v, i | mx, j | mn}});
                    }
                }
            }
        }
    }
    for (int i = 1; i < n; i++) {
        cout << d[i][1][1] << " ";
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值