【问题标题】:Algorithm for distribution of numbers in a matrix矩阵中数字分布的算法
【发布时间】:2016-10-11 20:04:01
【问题描述】:

这是我关于堆栈交换的第一个问题。我正在解决一个问题,我需要在矩阵中找到非负整数的分布,其中每行和每列加起来就是目标总数。我确信有一种算法可以做到这一点(或者一个理论说什么时候可以,什么时候不可以),但我在网上找到这个的运气并不好。

在附加的图像 (Image) 中,我有一个解决方案示例,我为该问题的特定实例找到了该解决方案,但没有涉及可定义的算法。灰色总计是每列和每行的目标总计,而浅蓝色总计是显示的当前分布的总计。在算法开始时只提供总数,所以我从一个空矩阵开始。

有人可以为我指出这个问题的资源/解决方案吗?

谢谢

【问题讨论】:

  • 仅整数? (这当然比分配连续值更难)仅严格正数?你看,细节很重要
  • 嗨,是的,仅限整数。
  • 正整数(包括0)。我已经更新了问题,谢谢。
  • @TinusWillemse 当您想添加信息作为评论的答案时,强烈建议您使用扩展信息编辑您的问题。最优分布是什么意思?
  • 嗨@TomerW,谢谢。我现在更新了我的问题。我现在意识到“最佳”不是正确的词,因为可能有多种解决方案可以满足约束。因此,我从问题中删除了“最佳”。

标签: algorithm optimization


【解决方案1】:

这看起来是个难题(可能是 np-hard)。

您最好的选择(忽略与领域相关的高度调整的算法)是组合优化的经典方法:

  • 元启发式(禁忌搜索、模拟退火等)
    • 需要一些调整/邻域定义...
  • SAT 求解器
    • 需要烦人的加法器仿真
    • 完全(可以证明,无解)
  • 约束编程
    • 易于配制
    • 可以调整
    • 完成
  • 整数编程
    • 易于制定,如下所示
    • 提供非常好的商业求解器
    • 完成 我将介绍后者的简单版本(这可能是其中最糟糕的方法;至少对于这个问题!)

它在 python 中实现并使用开源工具cvxpy(公式)和cbc(MIP-solver)。

代码

更新:先验修复一些元素值!

from cvxpy import *

targets_X = [17, 45, 7, 6]
targets_Y = [3 for i in range(11)] + [2 for i in range(21)]
fixed_elements_indices_x, fixed_elements_indices_y = [0, 1, 2], [0, 1, 2]
fixed_elements_values = [3, 3, 3]
dim_x, dim_y = len(targets_X), len(targets_Y)

# Vars
T = Int(dim_x, dim_y)

# Constraints
constraints = []
constraints.append(T >= 0)
constraints.append(sum_entries(T, axis=1) == targets_X)
constraints.append(sum_entries(T, axis=0).T == targets_Y)
constraints.append(T[fixed_elements_indices_x, fixed_elements_indices_y] == fixed_elements_values)
problem = Problem(Minimize(0), constraints)
problem.solve(CBC, verbose=True)

print(T.value.T)

输出

Clp0006I 0  Obj 0 Primal inf 159 (39)
Clp0006I 36  Obj 0 Primal inf 98.999998 (19)
Clp0006I 69  Obj 0
Clp0006I 69  Obj 0
Clp0000I Optimal - objective value 0
Cbc0045I No integer variables out of 128 objects (128 integer) have costs
Cbc0045I branch on satisfied N create fake objective Y random cost Y
Clp0000I Optimal - objective value 0
Node 0 depth 0 unsatisfied 0 sum 0 obj 0 guess 0 branching on -1
Clp0000I Optimal - objective value 0
Cbc0004I Integer solution of 0 found after 0 iterations and 0 nodes (0.00 seconds)
Cbc0001I Search completed - best objective 0, took 0 iterations and 0 nodes (0.00 seconds)
Cbc0035I Maximum depth 0, 0 variables fixed on reduced cost
Clp0000I Optimal - objective value 0
Clp0000I Optimal - objective value 0
[[ 3.  0.  0.  0.]
 [ 0.  3.  0.  0.]
 [ 0.  0.  3.  0.]
 [ 0.  3.  0.  0.]
 [ 0.  0.  3.  0.]
 [ 0.  0.  0.  3.]
 [ 0.  0.  0.  3.]
 [ 0.  2.  1.  0.]
 [ 0.  3.  0.  0.]
 [ 0.  3.  0.  0.]
 [ 0.  3.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 0.  2.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]
 [ 2.  0.  0.  0.]]

【讨论】:

  • 谢谢@sascha。如果通过说某些矩阵值无法更改(设置为 0)来修改问题,是否有办法使用您提到的方法?
  • @TinusWillemse 所有提到的方法都非常通用,可以很容易地结合起来。在上面,它只是多行代码。 编辑:我添加了它
  • 您可能不知道如何使用 C# 和 Google OR Tools 库制定上述解决方案?我试图弄清楚这一点,但整数编程和库对我来说都是新的。我需要将其集成到 .Net 应用程序中。
  • @TinusWillemse 如果 ORtools 提供 MIP 求解器,应该很容易做到这一点。唯一要做的就是将我的矩阵形式约束转换为它们的库支持的形式。如果你只看你的问题,这可能会更容易(简单的规则,如 sum == X 和 co.)。使用约束编程,可以更轻松地定义问题本身,但可能需要调整。阅读 lib 的文档,通过示例工作,当某些事情没有按预期工作时,发布一个新问题,询问特定问题。
  • 我设法在 ORtools 中对问题进行了编码。正如你所说,我只需要花时间去了解图书馆。感谢您的所有帮助。
【解决方案2】:

您可以使用maximum flow algorithm 在多项式时间内解决此问题。

设置一个源节点,每行一个节点,每列一个节点和一个目标节点。

从源到行节点的边的容量应该等于给定的行总和。

从 col 节点到 dest 的边的容量应该等于给定的列总和。

根据矩阵中允许的值,从行节点到 col 节点的边应具有容量。 (例如,如果第 x 行的条目,矩阵的 col y 必须为零,则将行节点 x 到 col 节点 y 的边的容量设置为 0。)

然后计算从源到目的地的最大流量,行节点和列节点之间的流量给出矩阵中的条目。

nxn 矩阵的解的复​​杂度为 O(n^3)。

【讨论】:

  • 这是否应该适用于 OP 对整体解决方案的渴望? (仅限整数)我不这么认为。约束矩阵看起来并不完全是单模的,即使它也无助于解决多商品流动问题。
  • 所有流都是整数,因为所有容量都是整数。 (考虑一种通过找到增广流来计算最大流量的方法,每次增广总是一个整数,因此流将保持整数。)
猜你喜欢
  • 2015-12-13
  • 2015-06-17
  • 2023-04-08
  • 2012-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
相关资源
最近更新 更多