Max_Flow dinic

本文深入探讨了使用网络流算法解决资源分配问题的方法,并通过实例展示了算法优化的重要性。从理论到实践,详细介绍了如何利用算法解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BeiJing2006 狼抓兔子
#include<stdio.h>
#include<string.h>
#define MAXD 1000100
#define MAXM 6000600
#define INF 1000000000
int N, M, T, e, first[MAXD], next[MAXM], u[MAXM], v[MAXM], flow[MAXM];
int q[MAXD], d[MAXD], work[MAXD], s[MAXD];
void add(int a, int b, int f)
{
    u[e] = a;
    v[e] = b;
    flow[e] = f;
    next[e] = first[a];
    first[a] = e;
    e ++;
}
void init()
{
    int i, j, a, b, f;
    T = N * M - 1;
    e = 0;
    for(i = 0; i <= T; i ++)
        first[i] = -1;
    for(i = 0; i < N; i ++)
        for(j = 1; j < M; j ++)
        {
            scanf("%d", &f);
            a = i * M + j - 1;
            b = i * M + j;
            add(a, b, f);
            add(b, a, f);
        }
    for(i = 1; i < N; i ++)
        for(j = 0; j < M; j ++)
        {
            scanf("%d", &f);
            a = (i - 1) * M + j;
            b = i * M + j;
            add(a, b, f);
            add(b, a, f);
        }
    for(i = 1; i < N; i ++)
        for(j = 1; j < M; j ++)
        {
            scanf("%d", &f);
            a = (i - 1) * M + j - 1;
            b = i * M + j;
            add(a, b, f);
            add(b, a, f);
        }
}
int bfs()
{
    int i, j, rear;
    for(i = 1; i <= T; i ++)
        d[i] = -1;
    d[0] = 0;
    rear = 0;
    q[rear ++] = 0;
    for(i = 0; i < rear ; i ++)
        for(j = first[q[i]]; j != -1; j = next[j])
            if(flow[j] && d[v[j]] == -1)
            {
                d[v[j]] = d[q[i]] + 1;
                if(v[j] == T)
                    return 1;
                q[rear ++] = v[j];
            }
    return 0;
}
int dinic()
{
    int i, j, cur, r, res = 0;
    while(bfs())
    {
        r = 0;
        cur = 0;
        for(i = 0; i <= T; i ++)
            work[i] = first[i];
        for(;;)
        {
            if(cur == T)
            {
                int a = INF, minr = r;
                for(i = 0; i < r; i ++)
                    if(flow[s[i]] < a)
                    {
                        a = flow[s[i]];
                        minr = i;
                    }
                for(i = 0; i < r; i ++)
                {
                    flow[s[i]] -= a;
                    flow[s[i] ^ 1] += a;
                }
                r = minr;
                cur = u[s[r]];
                res += a;
            }
            for(i = work[cur]; i != -1; i = next[i])
                if(flow[i] && d[v[i]] == d[cur] + 1)
                    break;
            work[cur] = i;
            if(i != -1)
            {
                s[r ++] = i;
                cur = v[i];
            }
            else
            {
                d[cur] = -1;
                if(r == 0)
                    break;
                r --;
                cur = u[s[r]];
            }
        }
    }
    return res;
}
int main()
{
    while(scanf("%d%d", &N, &M) == 2)
    {
        init();
        int res = dinic();
        printf("%d\n", res);
    }
    return 0;
}

import sys from collections import deque import matplotlib.pyplot as plt import networkx as nx import numpy as np plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题 plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 class DinicSourceSinkVisual: def __init__(self, n, edges, source, sink, visualize=True): """ :param n: 节点数 :param edges: 边列表 [(u, v, lb, ub)] :param source: 源点 :param sink: 汇点 :param visualize: 是否可视化 """ self.n = n self.source = source self.sink = sink self.original_edges = edges.copy() # 保存原始边 self.visualize = visualize self.fig, self.ax = plt.subplots(figsize=(14, 10)) self.fig.suptitle("有源汇上下界可行流算法动态可视化", fontsize=16) # 初始化超级源汇 self.super_source = n self.super_sink = n + 1 self.total_nodes = n + 2 # 计算每个节点的流量差 self.A = [0] * (n + 2) for u, v, lb, ub in self.original_edges: self.A[u] -= lb self.A[v] += lb # 添加源汇之间无限容量的边 - 关键修改 # 标准的有源汇上下界处理方法:添加t->s的无限容量边 edges.append((sink, source, 0, float('inf'))) # 创建Dinic数据结构 self.graph = [[] for _ in range(self.total_nodes)] self.level = [-1] * self.total_nodes self.cur = [0] * self.total_nodes self.edge_info = {} # 存储边信息 # 添加图中的边 self.edge_refs = [] for i, (u, v, lb, ub) in enumerate(edges): cap = ub - lb # 添加边并记录信息 self.add_edge(u, v, cap, (i, lb, ub, f"e{i}")) # 仅原始边(不包括后添加的sink->source边)记录在edge_refs中 if i < len(edges) - 1: # 最后一条是后添加的sink->source边 self.edge_refs.append((u, v, len(self.graph[u]) - 1, lb)) # 添加超级源汇的边 self.total_flow = 0 for i in range(n + 2): # 包含所有节点 if self.A[i] > 0: self.add_edge(self.super_source, i, self.A[i], (f"S→{i}", "super_source")) self.total_flow += self.A[i] elif self.A[i] < 0: self.add_edge(i, self.super_sink, -self.A[i], (f"{i}→T", "super_sink")) # 初始化可视化 if self.visualize: self.initialize_visualization() def add_edge(self, u, v, cap, info=None): """添加边并存储信息""" forward = [v, cap, 0, info] # [目标, 容量, 流量, 信息] reverse = [u, 0, 0, None] # 反向边 forward[2] = reverse reverse[2] = forward self.graph[u].append(forward) self.graph[v].append(reverse) # 存储边信息用于可视化 if info: self.edge_info[(u, v)] = { 'capacity': cap, 'flow': 0, 'info': info } return forward def bfs(self): """BFS分层并可视化""" self.level = [-1] * self.total_nodes queue = deque([self.super_source]) self.level[self.super_source] = 0 # 可视化:显示BFS搜索过程 if self.visualize: self.visualize_step(f"BFS分层: 访问超级源点S (L0)") plt.pause(1.0) while queue: u = queue.popleft() for i, edge in enumerate(self.graph[u]): v, cap, rev, info = edge if cap > 0 and self.level[v] == -1: self.level[v] = self.level[u] + 1 queue.append(v) # 可视化:显示新访问的节点 if self.visualize: if v < self.n: node_label = f"节点{v}" elif v == self.super_sink: node_label = "超级汇点T" else: node_label = "超级源点S" self.visualize_step(f"BFS分层: 访问{node_label} (L{self.level[v]})") plt.pause(0.3) return self.level[self.super_sink] != -1 def dfs(self, u, t, flow, path=None): """DFS查找增广路径并可视化""" if path is None: path = [] if u == t: # 可视化:显示找到的增广路径 if self.visualize: path_desc = "→".join( [f"{'S' if p == self.super_source else 'T' if p == self.super_sink else p}" for p in path + [t]] ) self.visualize_step(f"找到增广路径: {path_desc}\n流量: {flow}") plt.pause(1.5) return flow for i in range(self.cur[u], len(self.graph[u])): self.cur[u] = i edge = self.graph[u][i] v, cap, rev, info = edge if cap > 0 and self.level[v] == self.level[u] + 1: # 可视化:显示当前探索的边 if self.visualize: edge_desc = self.get_edge_description(u, v) self.visualize_step(f"探索: {edge_desc} (剩余容量: {cap})") plt.pause(0.5) f = self.dfs(v, t, min(flow, cap), path + [u]) if f > 0: # 更新边流量 edge[1] -= f rev[1] += f # 更新可视化信息 if (u, v) in self.edge_info: self.edge_info[(u, v)]['flow'] += f elif (v, u) in self.edge_info: # 处理反向边 self.edge_info[(v, u)]['flow'] -= f # 可视化:显示流量更新 if self.visualize: edge_desc = self.get_edge_description(u, v) self.visualize_step(f"更新: {edge_desc}\n增加流量: {f}") plt.pause(0.8) return f return 0 def max_flow(self): """计算最大流并动态可视化""" total_flow = 0 iteration = 1 while self.bfs(): self.cur = [0] * self.total_nodes if self.visualize: self.visualize_step(f"开始阶段 {iteration} (分层完成)") plt.pause(1.0) while True: flow = self.dfs(self.super_source, self.super_sink, float('inf')) if flow == 0: break total_flow += flow if self.visualize: self.visualize_step(f"阶段 {iteration} 完成\n累计流量: {total_flow}/{self.total_flow}") plt.pause(1.0) iteration += 1 # 检查可行解 if total_flow != self.total_flow: if self.visualize: self.visualize_step(f"无可行解!\n需求流量: {self.total_flow}, 实际流量: {total_flow}") plt.pause(3.0) return None # 计算原图中每条边的实际流量 flows = [] for u, v, idx, lb in self.edge_refs: # 跳过最后添加的sink->source边 if u == self.sink and v == self.source: continue edge = self.graph[u][idx] actual_flow = lb + edge[1] # 实际流量 = 下界 + 残余网络中的剩余容量 # 对于正常边,实际流量 = 下界 + 流量 # 但对于t->s边不计算 flows.append(actual_flow) if self.visualize: self.visualize_final_flow(flows) plt.pause(5.0) return flows def get_edge_description(self, u, v): """获取边的描述信息""" if u == self.super_source: return f"S → {v}" elif v == self.super_sink: return f"{u} → T" elif u == self.source and v == self.sink: return f"{u}→{v} (源汇边)" elif (u, v) in self.edge_info: info = self.edge_info[(u, v)]['info'] if isinstance(info, tuple) and len(info) > 3: return f"{u} → {v} ({info[3]})" return f"{u} → {v}" def initialize_visualization(self): """初始化可视化布局""" self.G = nx.DiGraph() # 添加节点 for i in range(self.n): self.G.add_node(i, label=f"{i}") self.G.add_node(self.super_source, label="S") self.G.add_node(self.super_sink, label="T") # 添加边 for u in range(self.total_nodes): for edge in self.graph[u]: v, cap, _, info = edge if cap > 0: # 只添加正向边 self.G.add_edge(u, v, capacity=cap, flow=0) # 创建环形布局 self.pos = {} # 普通节点布置在圆上 angles = np.linspace(0, 2 * np.pi, self.n, endpoint=False) for i in range(self.n): angle = angles[i] self.pos[i] = (np.cos(angle), np.sin(angle)) # 特殊节点位置 self.pos[self.source] = (0, 1.2) # 源点在上方 self.pos[self.sink] = (0, -1.2) # 汇点在下方 self.pos[self.super_source] = (-1.5, 0) # 超级源点在左侧 self.pos[self.super_sink] = (1.5, 0) # 超级汇点在右侧 # 初始绘图 self.ax.clear() # 节点颜色:普通节点-浅蓝,源汇点-浅绿,超级源汇-浅红 node_colors = [] for node in self.G.nodes(): if node == self.source or node == self.sink: node_colors.append('lightgreen') elif node == self.super_source or node == self.super_sink: node_colors.append('salmon') else: node_colors.append('lightblue') nx.draw_networkx_nodes(self.G, self.pos, node_size=800, node_color=node_colors) nx.draw_networkx_labels(self.G, self.pos, labels={n: d['label'] for n, d in self.G.nodes(data=True)}) # 绘制边 self.edge_collection = nx.draw_networkx_edges( self.G, self.pos, arrowstyle='->', arrowsize=20, edge_color='gray', width=1, ax=self.ax ) # 初始化边标签 self.edge_labels = {} for u, v in self.G.edges(): self.edge_labels[(u, v)] = self.ax.text(0, 0, "", fontsize=8, ha='center', va='center') self.ax.set_title("初始化网络", fontsize=14) self.ax.set_axis_off() plt.tight_layout() plt.pause(2.0) def visualize_step(self, message): """可视化当前步骤""" self.ax.clear() # 节点颜色 node_colors = [] for node in self.G.nodes(): if node == self.source or node == self.sink: node_colors.append('lightgreen') elif node == self.super_source or node == self.super_sink: node_colors.append('salmon') else: node_colors.append('lightblue') # 绘制节点 nx.draw_networkx_nodes(self.G, self.pos, node_size=800, node_color=node_colors) nx.draw_networkx_labels(self.G, self.pos, labels={n: d['label'] for n, d in self.G.nodes(data=True)}) # 绘制边并设置颜色和宽度 edge_colors = [] edge_widths = [] for u, v in self.G.edges(): # 获取当前边的状态 cap = self.G[u][v]['capacity'] flow = self.edge_info.get((u, v), {}).get('flow', 0) # 计算饱和度 saturation = flow / cap if cap > 0 else 0 # 使用颜色表示饱和度 edge_colors.append(plt.cm.RdYlGn(saturation)) # 使用宽度表示流量 edge_widths.append(1 + 3 * saturation) # 绘制边 nx.draw_networkx_edges( self.G, self.pos, arrowstyle='->', arrowsize=20, edge_color=edge_colors, width=edge_widths, ax=self.ax ) # 更新边标签 for (u, v), text in self.edge_labels.items(): # 获取边信息 cap = self.G[u][v]['capacity'] flow = self.edge_info.get((u, v), {}).get('flow', 0) # 特殊边处理 if u == self.super_source or v == self.super_sink: label = f"{flow}/{cap}" else: # 获取原始边信息 info = self.edge_info.get((u, v), {}).get('info', None) if info and isinstance(info, tuple): _, lb, ub, name = info actual_flow = lb + flow label = f"{name}: {actual_flow}/{ub}\n[{lb},{ub}]" else: label = f"{flow}/{cap}" # 计算边的中点位置 x = (self.pos[u][0] + self.pos[v][0]) / 2 y = (self.pos[u][1] + self.pos[v][1]) / 2 # 更新文本位置和内容 text.set_position((x, y)) text.set_text(label) self.ax.add_artist(text) # 显示当前信息 self.ax.set_title(message, fontsize=14) self.ax.set_axis_off() plt.tight_layout() plt.draw() def visualize_final_flow(self, flows): """可视化最终可行流分配(仅显示原图边)""" self.ax.clear() # 创建仅包含原图节点和边的子图 H = nx.DiGraph() for i in range(self.n): H.add_node(i, label=f"{i}") # 添加原图边(排除最后添加的sink->source边) for i, (u, v, lb, ub) in enumerate(self.original_edges): if i >= len(flows): continue H.add_edge(u, v, flow=flows[i], lb=lb, ub=ub, name=f"e{i}") # 使用原布局,但只保留原图节点的位置 pos = {k: v for k, v in self.pos.items() if k in H.nodes()} # 绘制节点 node_colors = ['lightgreen' if node == self.source or node == self.sink else 'lightblue' for node in H.nodes()] nx.draw_networkx_nodes(H, pos, node_size=800, node_color=node_colors) nx.draw_networkx_labels(H, pos) # 绘制边并设置颜色和宽度 edge_colors = [] edge_widths = [] for u, v in H.edges(): flow = H[u][v]['flow'] ub = H[u][v]['ub'] saturation = flow / ub edge_colors.append(plt.cm.RdYlGn(saturation)) edge_widths.append(1 + 3 * saturation) nx.draw_networkx_edges( H, pos, arrowstyle='->', arrowsize=20, edge_color=edge_colors, width=edge_widths, ax=self.ax ) # 添加边标签 edge_labels = {} for u, v in H.edges(): flow = H[u][v]['flow'] lb = H[u][v]['lb'] ub = H[u][v]['ub'] name = H[u][v]['name'] edge_labels[(u, v)] = f"{name}: {flow}\n[{lb},{ub}]" nx.draw_networkx_edge_labels(H, pos, edge_labels=edge_labels, font_size=8) self.ax.set_title("可行流分配结果(仅显示原图边)", fontsize=14) self.ax.set_axis_off() plt.tight_layout() plt.draw() def circulation_flow_visual(n, edges, source, sink): """有源汇上下界可行流求解与可视化""" # 创建可视化实例 dinic_visual = DinicSourceSinkVisual(n, edges, source, sink, visualize=True) # 计算可行流 flows = dinic_visual.max_flow() if flows is None: print("无可行流解") return None print("\n各边实际流量分配:") for i, (u, v, lb, ub) in enumerate(edges[:-1]): # 排除最后添加的sink->source边 print(f"边 {u}→{v} ({lb},{ub}): {flows[i]}") # 计算源点到汇点的总流量 source_flow = sum(flows[i] for i, (u, v, _, _) in enumerate(edges) if u == source) sink_flow = sum(flows[i] for i, (u, v, _, _) in enumerate(edges) if v == sink) print(f"\n源点({source})总输出流量: {source_flow}") print(f"汇点({sink})总输入流量: {sink_flow}") plt.show() # 保持窗口打开 return flows if __name__ == "__main__": # 15节点有可行解的网络示例 - 简化版 print("=" * 50) print("15节点网络的有源汇上下界可行流计算 (保证有可行解)") # 简化设计:确保网络平衡 n = 15 edges = [ # 源点→核心节点 (0, 1, 5, 10), (0, 2, 5, 10), # 核心环状结构 (1, 2, 0, 5), (2, 3, 2, 8), (3, 4, 2, 8), (4, 1, 0, 5), # 核心→中间节点 (1, 5, 1, 4), (2, 6, 1, 4), (3, 7, 1, 4), (4, 8, 1, 4), # 中间层平衡结构 (5, 6, 0, 5), (6, 7, 0, 5), (7, 8, 0, 5), (8, 5, 0, 5), # 中间→汇点 (5, 14, 3, 6), (6, 14, 3, 6), (7, 14, 2, 5), (8, 14, 2, 5), # 连接外围节点 (1, 9, 0, 3), (2, 10, 0, 3), (3, 11, 0, 3), (4, 12, 0, 3), (9, 13, 0, 3), (10, 13, 0, 3), (11, 13, 0, 3), (12, 13, 0, 3), (13, 14, 0, 5) # 汇点入口 ] # 设置源点和汇点 source = 0 # 节点0作为源点 sink = 14 # 节点14作为汇点 # 计算并可视化可行流 flows = circulation_flow_visual(n, edges, source, sink) 修改代码,使得其能够解决有源汇上下界最小流问题, 给出修改后的完整代码
06-15
内容概要:本文详细介绍了Rust在系统编程中的应用,包括基础知识、核心技术及开发流程。首先阐述了Rust语言的基础及环境搭建,强调了其强类型系统和现代语法。接着深入探讨了所有权机制与内存安全,指出Rust通过所有权系统确保内存安全,避免悬垂指针和内存泄漏。再者,讲解了Rust的并发编程模型,通过消息传递和无数据竞争的线程模型实现安全并发。此外,讨论了Rust在底层硬件访问与嵌入式开发中的应用,展示了其在资源受限平台上的适应性。随后,介绍了系统调用与内核模块开发,说明了Rust如何调用操作系统底层API并实现与现有内核代码的无缝集成。还提及了性能优化与调试技巧,如使用编译器优化选项和工具链支持。最后,通过实战项目案例解析和社区资源展望,展示了Rust在系统编程领域的潜力和发展前景。; 适合人群:有一定编程基础,尤其是对系统编程感兴趣的开发者,包括操作系统内核开发、驱动程序编写、嵌入式系统开发等领域的工程师。; 使用场景及目标:①学习Rust语言的基础知识和环境搭建,掌握强类型系统和现代语法;②理解所有权机制与内存安全,避免传统系统编程中的常见错误;③掌握并发编程模型,实现安全高效的多线程操作;④了解底层硬件访问和嵌入式开发,适应资源受限平台;⑤掌握系统调用与内核模块开发,实现与现有系统的无缝集成;⑥学习性能优化与调试技巧,提高系统软件的运行效率和稳定性;⑦通过实战项目案例解析,掌握系统编程的实际应用。; 其他说明:Rust作为系统编程的新选择,不仅提升了传统系统软件的安全性,还通过现代语言特性和工具链优化了开发效率。开发者应充分利用Rust的特性,构建更加健壮、高效的系统软件,迎接未来计算机领域的新挑战。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值