382. K取方格数(图论,费用流,拆点,上下界可行流,网格图模型)

探讨了在给定网格中通过K条路线取整数的优化策略,借助费用流模型解决并计算最大和。

在一个 N×N 的矩形网格中,每个格子里都写着一个非负整数。

可以从左上角到右下角安排 K 条路线,每一步只能往下或往右,沿途经过的格子中的整数会被取走。

若多条路线重复经过一个格子,只取一次。

求能取得的整数的和最大是多少。

输入格式

第一行包含两个整数 N 和 K。

接下来 N 行,每行包含 N 个不超过 1000 的整数,用来描述整个矩形网格。

输出格式

输出一个整数,表示能取得的最大和。

数据范围

1≤N≤50,
0≤K≤10

输入样例:
3 2
1 2 3
0 2 1
1 4 2
输出样例:
15

解析: 

本题我们需要在一个 n×n 的矩阵,每个格子上都写着一个非负整数,我们指定 k 条路线,每一步只能往下或往右,每个格子上的数只能取一次,求如何指定这 k 条路线,能让取得的整数和最大。

像这种方格取数问题,存在简单版本,如指定一条路线或两条路线的问题,可以使用线性 dp 来求,但是本题由于最多会有 10 条路径,用 dp 会超时,所以这里考虑用费用流来解决。

首先我们先不去考虑每个格子只能取一次的问题,我们先设法将路线转化成流。起点是左上角,终点是右下角,所有的路线都是从左上角走到右下角。所以我们可以建立一个源点和一个汇点,从源点向左上角连一条容量为 k 的边,从汇点向右下角连一条容量为 k 的边,表示有 k 条路线从左上角走到右下角。然后每个格子都可以向右和向下走,因此从每个格子向右和向下两个格子连边,且每个格子能走多次,没有限制,因此这些边的容量都是 +∞。这样我们就在网格图上建立了一个流网络。

此时可以发现流网络的任意一个可行流和原问题的任意一个方案都是一

上下界网络是在普通网络基础上发展而来的一类问题,它对每边的量添加了上下界的限制。 ### 原理 普通的网络问题通常只对边的最大量(容量)进行限制,而上下界网络在此基础上,还规定了每量的最小值。这使得在求解网络时,不仅要满足量守恒(入一个节量等于出该节量)和容量限制,还要满足每量的下界要求。其核心原理依然基于量守恒定律,不过在构建和求解网络时需要考虑更多的约束件。 ### 算法 - **无源汇上下界可行**: - 首先,对原网络进行改造,添加一个超级源 \(S'\) 和超级汇 \(T'\)。 - 对于每边 \((u, v)\),其下界为 \(b(u, v)\),上界为 \(c(u, v)\),将其分为两边,一是从 \(u\) 到 \(v\) 容量为 \(c(u, v)-b(u, v)\) 的边,另一是从超级源 \(S'\) 到 \(v\) 容量为 \(b(u, v)\) 的边,以及从 \(u\) 到超级汇 \(T'\) 容量为 \(b(u, v)\) 的边。 - 然后在新网络上求解从 \(S'\) 到 \(T'\) 的最大。如果最大能够使得从 \(S'\) 出发的所有边都满,那么原网络存在可行,否则不存在。 - **有源汇上下界最大**: - 先求解无源汇上下界可行。 - 若存在可行,添加一从汇 \(T\) 到源 \(S\) 容量为无穷大的边,将有源汇网络转化为无源汇网络。 - 再次求解新网络的最大,最终的有源汇上下界最大为此次最大减去 \(T\) 到 \(S\) 边的量。 - **有源汇上下界最小**: - 同样先求解无源汇上下界可行。 - 添加从 \(T\) 到 \(S\) 容量为无穷大的边。 - 去掉超级源 \(S'\) 和超级汇 \(T'\),然后从 \(S\) 到 \(T\) 求最小割,最小割对应的量即为有源汇上下界最小。 ### 应用 - **项目安排问题**:在多个项目和资源的分配中,每个项目对资源的使用有一定的上下界要求,通过上下界网络可以合理安排资源,使得所有项目都能满足其基本需求,同时尽量优化资源的分配。 - **任务调度问题**:在任务调度场景中,每个任务的执行时间有一定的上下界限制,通过构建上下界网络模型,可以找到一种合理的调度方案,使得所有任务能够在规定的时间范围内完成。 - **运输问题**:在货物运输中,每运输路线有运输量的上下界,使用上下界网络可以规划出满足这些限制件的最优运输方案。 ```python # 以下是一个简单的伪代码示例,用于说明上下界网络的基本思路 # 这里只是概念性的代码,实际实现会更复杂 # 假设已经有了图的表示和最大算法 # 构建新图以求解无源汇上下界可行 def build_new_graph(graph, lower_bounds, upper_bounds): new_graph = ... # 初始化新图 # 进行边的分和添加超级源、超级汇等操作 return new_graph # 求解无源汇上下界可行 def feasible_flow(graph, lower_bounds, upper_bounds): new_graph = build_new_graph(graph, lower_bounds, upper_bounds) max_flow = max_flow_algorithm(new_graph) # 调用最大算法 # 判断是否存在可行 if is_feasible(max_flow): return True return False # 求解有源汇上下界最大 def max_flow_with_bounds(graph, source, sink, lower_bounds, upper_bounds): if feasible_flow(graph, lower_bounds, upper_bounds): # 添加 T 到 S 容量为无穷大的边 graph.add_edge(sink, source, float('inf')) new_max_flow = max_flow_algorithm(graph) # 计算最终的最大 final_max_flow = new_max_flow - ... # 减去 T 到 S 边的量 return final_max_flow return 0 # 求解有源汇上下界最小 def min_flow_with_bounds(graph, source, sink, lower_bounds, upper_bounds): if feasible_flow(graph, lower_bounds, upper_bounds): graph.add_edge(sink, source, float('inf')) # 去掉超级源和超级汇 new_graph = remove_super_nodes(graph) min_cut = min_cut_algorithm(new_graph) # 调用最小割算法 return min_cut return 0 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值