Dijkstra 求最短路 最大流

本文探讨了Dijkstra算法在解决最短路问题之外的另一个应用场景——最大流问题。通过每次确定一个点来更新每个节点的允许最大流,并详细解释了算法的调整步骤。以POJ1797 'HeavyTransportation'为例,展示了如何利用Dijkstra算法解决实际问题。
原来Dijkstra算法不光只能求最短路问题,还能求最大流问题~~~Dijkstra <wbr>求最短路 <wbr>最大流
最短路问题时,Dijkstra算法的基本思想:
 
邻接矩阵w[x][y]保存x和y间的距离(别的设为INF,表示不连通,设为-1也行,后来更新加一个if(w[x][y]>=0)),数组d保存通过已经确定的点从起点到每个点的最短路。初始化d[0]=0,别的都是INF。循环n次,每次确定一个点,最后的d[n]就是答案。
 怎么每次确定一个点呢?就是在所有还未确定的点中找到d最小的点。因为如果d[x]是剩下的里面最小的,x这个点的最短路已经被确定(假设通过别的点再到x,起点到别的点路径本来就比到x长,再加上那个点到x的距离就更长了。。)找到x之后把x标记为访问,然后对于所有从x出发的边(x,y),更新d[y]=min(d[y],d[x]+w[x][y])。
Dijkstra算法只能用于边权均为正的情况。复杂度O(N^2)

具体代码:

memset(vis,0,sizeof(vis));
int i;
for(i=0; i<n; i++) d[i]=(i==0?0:INF);
for(i=0; i<n; i++)
{
    int x,y,m=INF;
    for(y=0; y<n; y++) if(!vis[y]&&d[y]<=m) m=d[x=y];
    vis[x]=1;
    for(y=0; y<n; y++) d[y]=d[y]<d[x]+w[x][y]?d[y]:d[x]+w[x][y];
}



若要打印节点,只要把d[y]=d[y]<d[x]+w[x][y]?d[y]:d[x]+w[x][y]改成
if(d[y]>d[x]+w[x][y])
{
   d[y]=d[x]+w[x][y];
   fa[y]=x;
}

但是又怎么用Dijkstra求最大流呢?其实也是每次确定一个点,更新此时每个点能通过的最大流。初始化d[0]=INF(一开始有无穷大的流),别的都是-1(代表没有)。不连通的w[x][y]也设为-1。每次循环找到d最大的点(能允许的流最大),更新的时候注意是d[y]=d[y]>min(d[x],w[x][y])?d[y]:min(d[x],w[x][y])。
总之就是把原来的最小都换成现在的最大。。

POJ 1797
Heavy Transportation
Time Limit: 3000MS Memory Limit: 30000K
Total Submissions: 17277 Accepted: 4536

Description

Background
Hugo Heavy is happy. After the breakdown of the Cargolifter projecthe can now expand business. But he needs a clever man who tells himwhether there really is a way from the place his customer has buildhis giant steel crane to the place where it is needed on which allstreets can carry the weight.
Fortunately he already has a plan of the city with all streets andbridges and all the allowed weights.Unfortunately he has no ideahow to find the the maximum weight capacity in order to tell hiscustomer how heavy the crane may become. But you surely know.

Problem
You are given the plan of the city, described by the streets (withweight limits) between the crossings, which are numbered from 1 ton. Your task is to find the maximum weight that can be transportedfrom crossing 1 (Hugo's place) to crossing n (the customer'splace). You may assume that there is at least one path. All streetscan be travelled in both directions.

Input

The first line contains the number of scenarios(city plans). For each city the number n of street crossings (1<= n <= 1000) and number m of streetsare given on the first line. The following m lines contain triplesof integers specifying start and end crossing of the street and themaximum allowed weight, which is positive and not larger than1000000. There will be at most one street between each pair ofcrossings.

Output

The output for every scenario begins with a linecontaining "Scenario #i:", where i is the number of the scenariostarting at 1. Then print a single line containing the maximumallowed weight that Hugo can transport to the customer. Terminatethe output for the scenario with a blank line.

Sample Input

1
3 3
1 2 3
1 3 4
2 3 5

Sample Output

Scenario #1:
4



代码:
#include<stdio.h>
#include<math.h>
#include<string.h>
int map[1010][1010],d[1010],vis[1010],n,m;
int min(int a,int b)
{
    return a<b?a:b;
}
void dijkstra()
{
    memset(vis,0,sizeof(vis));
    int i;
    for(i=1; i<=n; i++) d[i]=(i==1?1000000:-1);
    for(i=1; i<=n; i++)
    {
        int x,m=-1,y;
        for(y=1; y<=n; y++) if(!vis[y]&&d[y]>m) m=d[x=y];
        vis[x]=1;
        for(y=1; y<=n; y++) if(map[x][y]>=0&&!vis[y])d[y]=d[y]>min(d[x],map[x][y])?d[y]:min(d[x],map[x][y]);
    }
}
int main()
{
    int N,T;
    scanf("%d",&N);
    for(T=1; T<=N; T++)
    {
        int a,b,c;
        memset(map,-1,sizeof(map));
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            map[a][b]=map[b][a]=c;
        }
        dijkstra();
        printf("Scenario #%d:\n",T);
        printf("%d\n",d[n]);
        if(T<N) puts("");
    }
    return 0;
}

### 短路最大流算法概念 短路最大流问题是网络流理论中的一个重要分支,它不仅关注如何在网络中传输流量达到大化,还考虑了每条边上的成本因素。这类问题通常涉及两个核心子问题:**最大流问题**和**小费用问题**。 #### 1. **最大流问题** 最大流问题的目标是在给定的有向图 \( G(V, E) \) 中找到从源点 \( s \) 到汇点 \( t \) 的大可行流量。解决这一问题的经典算法包括 Edmonds-Karp (EK)[^3] 和 Dinic 算法[^3]。这些算法基于增广路径的思想,通过不断寻找残余网络中的可增加流量的路径来更新当前流值,直至无法再找到新的增广路径。 #### 2. **小费用问题** 小费用问题则进一步引入了单位流量的成本因子,目标是小化总运输成本的同时满足特定流量需。常用的方法包括 Bellman-Ford 算法及其优化版本 SPFA 算法[^1] 来处理带有负权重的情况,以及 Dijkstra 算法用于正权重情况下的高效解[^2]。 --- ### 实现方法 以下是几种常见算法的具体实现方式: #### (一)Edmonds-Karp (EK) 算法 EK 是 Ford-Fulkerson 方法的一个具体实现形式,利用 BFS 寻找增广路径并更新残留容量矩阵。 ```python from collections import deque def bfs(residual_graph, parent, source, sink): visited = [False] * len(residual_graph) queue = deque([source]) visited[source] = True while queue: u = queue.popleft() for v in range(len(residual_graph)): if not visited[v] and residual_graph[u][v] > 0: queue.append(v) visited[v] = True parent[v] = u if v == sink: return True return False def edmonds_karp(graph, source, sink): n = len(graph) residual_graph = [[graph[i][j] for j in range(n)] for i in range(n)] max_flow = 0 parent = [-1] * n while bfs(residual_graph, parent, source, sink): path_flow = float('Inf') s = sink while s != source: path_flow = min(path_flow, residual_graph[parent[s]][s]) s = parent[s] max_flow += path_flow v = sink while v != source: u = parent[v] residual_graph[u][v] -= path_flow residual_graph[v][u] += path_flow v = parent[v] return max_flow ``` #### (二)Dinic 算法 相比 EK,Dinic 使用分层图技术减少多次调用 BFS 所带来的开销。 ```python class Edge: def __init__(self, to, capacity, rev_index): self.to = to self.capacity = capacity self.rev_index = rev_index def dinic_bfs(level_graph, graph, source, sink): level_graph[:] = [-1]*len(graph) level_graph[source] = 0 q = [source] for node in q: for edge in graph[node]: if edge.capacity > 0 and level_graph[edge.to] < 0: level_graph[edge.to] = level_graph[node]+1 q.append(edge.to) return level_graph[sink] >= 0 def dfs(current_node, flow, graph, level_graph, iter_pointer, sink): if current_node == sink or flow == 0: return flow for &i=iter_pointer[current_node]; i<len(graph[current_node]); ++i: edge = graph[current_node][i] if edge.capacity>0 && level_graph[edge.to]==level_graph[current_node]+1: d = dfs(edge.to,min(flow,edge.capacity),graph,level_graph,iter_pointer,sink) if d>0: edge.capacity-=d graph[edge.to][edge.rev_index].capacity+=d return d return 0 def dinic_maxflow(graph, source, sink): N=len(graph) level_graph=[-1]*N iter_pointer=[0]*N total_flow=0 while(dinic_bfs(level_graph,graph,source,sink)): iter_pointer=[0]*N f=-1 while(f:=dfs(source,float('inf'),graph,level_graph,iter_pointer,sink))>0: total_flow+=f return total_flow ``` #### (三)Bellman-Ford 及其变种 SPFA 适用于存在负权边的情形下计算单源短距离。 ```python import sys def bellman_ford(edges, V, src): dist = [sys.maxsize] * V dist[src] = 0 for _ in range(V - 1): for u, v, w in edges: if dist[u] != sys.maxsize and dist[u] + w < dist[v]: dist[v] = dist[u] + w # Check negative cycle for u, v, w in edges: if dist[u] != sys.maxsize and dist[u] + w < dist[v]: raise ValueError("Graph contains a negative weight cycle") return dist # Example usage of SPFA as an optimized version of Bellman-Ford. from collections import deque def spfa(edges, adj_list, V, src): dist = [float('inf')] * V in_queue = [False] * V dist[src], Q = 0, deque([src]) while Q: u = Q.popleft(); in_queue[u]=False for v,w in adj_list[u]: if dist[v]>dist[u]+w: dist[v]=dist[u]+w if not in_queue[v]: Q.append(v);in_queue[v]=True return dist ``` --- ### 性能分析与适用场景 | 算法名称 | 时间复杂度 | 特性 | |----------------|--------------------|----------------------------------------------------------------------| | Edmonds-Karp | \( O(VE^2) \) | 易于理解和实现;适合小型稠密图 | | Dinic | \( O(V^2E) \) | 效率更高;推荐用于稀疏图 | | Bellman-Ford | \( O(VE) \) | 支持负权边 | | SPFA | 平均接近 \( O(E) \)| 队列优化版 Bellman-Ford;实际表现依赖输入数据 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值