当前位置:首页 > 提高组 > 洛谷P1073题解:最短路问题的SPFA算法优化与双向边处理

洛谷P1073题解:最短路问题的SPFA算法优化与双向边处理

3个月前 (09-07)

洛谷P1073题解:最短路问题的SPFA算法优化与双向边处理 SPFA算法 最短路径 动态规划 NOIP 提高组 图论 队列 有向图 第1张

一、题目解读

洛谷P1073题要求在一个有向图中,通过处理双向边和单向边,计算从起点到终点的最大利润路径。题目中包含两种边:单向边(仅允许单向通行)和双向边(可双向通行),需要利用动态规划思想结合图论算法求解最优解。

二、解题思路

采用SPFA(Shortest Path Faster Algorithm)算法,通过两次最短路径计算实现解题。首先,构建原G和反向图rG,分别处理正向和反向的最短路径。关键在于双向边的特殊处理:若边权为2,则在正反图中均添加该边,确保双向通行性。通过两次SPFA分别计算最小代价和最大代价路径,最终取两者之差的最大值作为答案。

三、解题步骤

1. 读入节点数n、边数m及节点价格数组price。

2. 构建图结构:根据边类型(单向/双向)向G和rG添加边。

3. 运行正向SPFA(min_price数组),计算从起点1到各点的最小价格路径。

4. 运行反向SPFA(max_price数组),计算从终点n到各点的最大价格路径。

5. 遍历各节点,取max_price - min_price的最大值作为最终答案。

6. 输出结果。

四、代码与注释

#include <iostream>  

#include <vector>  

#include <queue>  

#include <algorithm>  

using namespace std;  


const int MAXN = 100010;  

const int INF = 0x3f3f3f3f;  


struct Edge {  

    int to, cost; // 边终点与权值  

};  


vector<Edge> G[MAXN], rG[MAXN]; // 正向图与反向图  

int min_price[MAXN], max_price[MAXN]; // 最小/最大路径价格  

int price[MAXN]; // 节点价格  

bool vis[MAXN]; // 节点访问标记  


// SPFA函数(is_min控制最小/最大路径计算)  

void spfa(int s, vector<Edge> graph[], int dist[], bool is_min) {  

    fill(dist, dist + MAXN, is_min? INF : -INF); // 初始化距离值  

    fill(vis, vis + MAXN, false);  

    queue<int> q;  

    dist[s] = price[s]; // 起点价格作为初始值  

    q.push(s);  

    vis[s] = true;  


    while (!q.empty()) {  

        int u = q.front(); q.pop();  

        vis[u] = false;  

        for (Edge &e : graph[u]) { // 遍历邻居节点  

            int v = e.to;  

            int new_val = is_min? min(dist[u], price[v])  : max(dist[u], price[v]);  // 根据is_min选择min或max  

            if ((is_min && new_val < dist[v]) || (!is_min && new_val > dist[v])) {  

                dist[v] = new_val; // 更新路径值  

                if (!vis[v]) {  

                    q.push(v);  

                    vis[v] = true;  

                }  

            }  

        }  

    }  

}  


int main() {  

    ios::sync_with_stdio(false);  

    cin.tie(nullptr);  


    int n, m;  

    cin >> n >> m;  

    for (int i = 1; i <= n; ++i) {  

        cin >> price[i]; // 读入节点价格  

    }  


    for (int i = 0; i < m; ++i) {  

        int x, y, z;  

        cin >> x >> y >> z;  

        G[x].push_back({y, z}); // 添加正向边  

        rG[y].push_back({x, z}); // 添加反向边  

        if (z == 2) { // 双向边特殊处理  

            G[y].push_back({x, z});  

            rG[x].push_back({y, z});  

        }  

    }  


    spfa(1, G, min_price, true); // 正向SPFA计算最小价格  

    spfa(n, rG, max_price, false); // 反向SPFA计算最大价格  


    int ans = 0;  

    for (int i = 1; i <= n; ++i) {  

        if (min_price[i]!= INF && max_price[i]!= -INF) {  

            ans = max(ans, max_price[i] - min_price[i]); // 更新最大利润  

        }  

    }  


    cout << ans << endl;  

    return 0;  

}  

五、总结

本文通过SPFA算法结合双向边处理,高效解决了洛谷P1073的最短路问题。关键在于:

1. 构建正反向图以支持双向边通行;

2. 利用min/max分支实现灵活路径计算;

3. 通过两次SPFA遍历获取最优路径差值。

该解法时间复杂度O(mn),适用于稀疏图场景,为动态规划与图论结合的典型实例。


原创内容 转载请注明出处

分享给朋友:

相关文章

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

一、题目解读    2024年GESP(青少年软件编程能力等级考试)五级中的“武器强化”(洛谷平台题目编号B4071)是一道典型的算法优化问题。题目要求通过合理...

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

一、题目解读牛客12576题是一道经典的算法题,要求给定起点N和终点M,求解从N到M的最少跳跃次数。题目考察的核心在于路径优化与动态规划思想,需结合数论中的质因数分解技巧,通过合理设计算法降低时间复杂...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

一、题目解读CSP-J 2019年的“公交换乘”题目(洛谷P5661)要求模拟地铁与公交交替出行的费用计算。题目核心在于地铁消费会产生优惠券,而公交可在45分钟内使用优惠券抵扣车费。需要处理n条出行记...

2017年 NOIP 提高组 逛公园(洛谷P3953)题解:代码解析与优化

2017年 NOIP 提高组 逛公园(洛谷P3953)题解:代码解析与优化

一、题目解读    2017年NOIP提高组“逛公园”题目(洛谷P3953)要求在有向图中计算从起点到终点满足特定条件的路径数量。题目难点在于处理路径长度限制与...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。