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

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

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


原创内容 转载请注明出处

分享给朋友:

相关文章

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

题目重解给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们的目标是找到一条路径,使得路径上经过的数字总和最大。这个问题在实际中有许多应用场景,如最优路径规划、...

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

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

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

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

一、题目解读    1999年NOIP提高组“导弹拦截”问题(对应洛谷P1020)要求设计导弹拦截系统:给定一组导弹高度数据,需计算最少拦截系统数量,并求最多能...

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

一、题目解读洛谷2789题要求计算n条直线在平面上两两相交时产生的不同交点数量。题目强调“不同”交点,需排除重复情况。解题关键在于如何高效枚举所有可能的交点组合,并避免重复计数。二、解题思路参考代码采...

LeetCode 2222题解析:高效统计"010"与"101"子序列数量的算法优化

LeetCode 2222题解析:高效统计"010"与"101"子序列数量的算法优化

一、题目解读题目要求计算给定字符串中包含"010"或"101"子序列的数量。关键难点在于高效遍历所有子序列,避免重复计算。传统暴力解法时间复杂度O(n^3)会超...

牛客网288555题解题指南:动态规划求解小红的暑假(附代码解析)

牛客网288555题解题指南:动态规划求解小红的暑假(附代码解析)

一、题目解读牛客网288555题要求解决一个组合数学问题:有三位朋友,每天需邀请其中一位参加聚会,但不能连续两天邀请同一位朋友。给定天数n,求满足条件的不同邀请方案总数。题目考察动态规划、状态转移及组...

发表评论

访客

看不清,换一张

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