【SPFA】最长路(洛谷)

本文介绍了使用SPFA算法解决有向无环图中最长路问题的方法。详细讲解了题目要求,输入输出格式,并提供了样例及解题思路。通过将最短路算法稍作修改,可以找到从顶点1到顶点n的最大路径长度。

最长路


题目

  • 设G为有n个顶点的有向无环图,G中各顶点的编号为1到n,且当为G中的一条边时有i < j。设w(i,j)为边的长度,请设计算法,计算图G中<1,n>间的最长路径。

输入

  • 输入文件longest.in的第一行有两个整数n和m,表示有n个顶点和m条边,接下来m行中每行输入3个整数a,b,v(表示从a点到b点有条边,边的长度为v)。

输出

  • 输出文件longest.out,一个整数,即1到n之间的最长路径.如果1到n之间没连通,输出-1。

输入样例

2 1
1 2 1

输出样例

1

说明

20%的数据,n≤100,m≤1000

40%的数据,n≤1,000,m≤10000

100%的数据,n≤1,500,m≤50000,最长路径不大于10^9


解题思路

其实这道题看起来好像很难,但是就是打一个最短路再改成最长的就即可.


程序如下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
int n,a[2001][3],x,y,M,z,s,t,g
洛谷 P3357 是一个经典的网络流问题,具体涉及最大流与最小割的应用。该问题通常被称为“最长k可重线段集”问题或类似的最大收益问题,其核心在于如何利用网络流算法对问题进行建模和求解。 ### 问题解析 该问题可以被理解为在给定一系列线段的情况下,选出若干互不重叠的线段,使得它们的总权值最大。这一问题可以通过构建一个流网络,将其转化为最大流问题,进而使用最小割模型进行求解。 具体而言,需要将线段的端点作为图中的节点,并依据线段的权值和重叠限制构建边权。通过引入源点和汇点,并设置合适的容量限制,可以将问题转化为在网络中寻找最大流的过程。 ### 算法实现 常用的解决方案是使用 **最小费用最大流** 或 **最大流 Dinic 算法** 对问题进行建模。以下是一个基于 Dinic 算法的基本实现框架: ```cpp #include <iostream> #include <vector> #include <queue> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 100005; const int INF = 1e9; struct Edge { int to, rev, capacity, cost; Edge(int t, int r, int c, int co) : to(t), rev(r), capacity(c), cost(co) {} }; vector<Edge> graph[MAXN]; void addEdge(int u, int v, int cap, int cost) { graph[u].push_back(Edge(v, graph[v].size(), cap, cost)); graph[v].push_back(Edge(u, graph[u].size() - 1, 0, -cost)); } int dist[MAXN], inqueue[MAXN], pre[MAXN], record[MAXN]; bool spfa(int s, int t) { queue<int> q; memset(dist, 0x3f, sizeof(dist)); memset(inqueue, 0, sizeof(inqueue)); dist[s] = 0; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); inqueue[u] = 0; for (int i = 0; i < graph[u].size(); i++) { Edge &e = graph[u][i]; if (e.capacity > 0 && dist[e.to] > dist[u] + e.cost) { dist[e.to] = dist[u] + e.cost; pre[e.to] = u; record[e.to] = i; if (!inqueue[e.to]) { q.push(e.to); inqueue[e.to] = 1; } } } } return dist[t] < INF; } int minCostMaxFlow(int s, int t, int maxf) { int flow = 0, cost = 0; while (spfa(s, t)) { int delta = INF; for (int i = t; i != s; i = pre[i]) { Edge &e = graph[pre[i]][record[i]]; delta = min(delta, e.capacity); } for (int i = t; i != s; i = pre[i]) { Edge &e = graph[pre[i]][record[i]]; e.capacity -= delta; graph[e.to][e.rev].capacity += delta; cost += delta * e.cost; } flow += delta; } return cost; } int main() { int n, k; cin >> n >> k; // 构建图的逻辑 // 添加源点、汇点以及相应的边 // 调用 addEdge 函数添加边 // 输出结果 cout << minCostMaxFlow(0, 2 * n + 1, k); return 0; } ``` 上述代码框架中,`addEdge` 函数用于向图中添加边,`minCostMaxFlow` 函数用于计算最小费用最大流[^3]。实际实现中,需要根据问题的具体输入构造图的结构,并合理设置源点和汇点的连接方式。 ### 优化与复杂度分析 - **时间复杂度**:Dinic 算法的时间复杂度为 $O(N^2M)$,其中 $N$ 为节点数,$M$ 为边数。对于稀疏图,该算法表现良好。 - **空间复杂度**:取决于图的规模,通常为 $O(N + M)$。 ### 注意事项 - 需要特别注意线段端点的处理,尤其是重叠点的判定。 - 图的构建必须严格符合题意,否则可能导致错误的最小割或最大流计算。 - 在多次查询的情况下,可以考虑对图进行预处理以提高效率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值