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

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

7小时前

洛谷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),适用于稀疏图场景,为动态规划与图论结合的典型实例。


原创内容 转载请注明出处

分享给朋友:

相关文章

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

一、题目解读小杨买饮料是GESP 2023年六级认证考试中的一道经典动态规划题目,考察学生对背包问题的理解和应用能力。题目描述小杨需要购买n种饮料,每种饮料有特定的体积w和价格v,他要在不超过容量l的...

洛谷4554题解:BFS算法优化最短路径求解(附代码详解)

洛谷4554题解:BFS算法优化最短路径求解(附代码详解)

一、题目解读洛谷4554题要求在一个n×m的网格中,计算从点(x1,y1)到点(x2,y2)的最短路径距离。路径上的每个格子包含字符,若相邻格子字符不同,则需要额外步数。题目核心在于处理字符差异对路径...

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

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

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

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

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

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

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

一、题目解读    “生命之树”是一道经典的树形结构问题,要求计算一棵带权树中,以某个节点为根的最大子树权值和。题目输入为n个节点及边信息,每个节点有权值wi,...

力扣931题最小下降路径和解析 动态规划解法 LeetCode解题技巧

力扣931题最小下降路径和解析 动态规划解法 LeetCode解题技巧

一、题目解读力扣931题「Minimum Falling Path Sum」(最小下降路径和)要求在一个n x n的整数矩阵中,计算从顶部到底部的最小路径和。路径只能从每个位置向下或对角线移动(即向下...

发表评论

访客

看不清,换一张

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