这是我关于堆栈交换的第一个问题。我正在研究一个问题,我需要在矩阵中找到非负整数的分布,其中每行和每列总计达到目标总和。我确信有一种算法可以做到这一点(或者一种理论说明何时可行,何时不行)但我没有太多运气在网上找到它。
在附图中(Image)我有一个解决方案的例子,我找到了一个特定的问题实例,但没有涉及可定义的算法。灰色总计是每列和每行的目标总计,而浅蓝色总计是显示的当前分布的总计。在算法的开头只提供了总数,所以我从一个空矩阵开始。
有人可以指点我这个问题的资源/解决方案吗?
谢谢
答案 0 :(得分:0)
这看起来像一个难题(可能 np-hard )。
最好的选择(忽略依赖于域的高度调优算法)是组合优化的经典方法:
它在python中实现并使用开源工具cvxpy(配方)& cbc(MIP解算器)。
更新:修复一些元素值a-priori!
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.]]
答案 1 :(得分:0)
您可以使用maximum flow algorithm在多项式时间内解决此问题。
设置源节点,每行的节点,每列的节点和目标节点。
从源节点到行节点的边缘应具有等于给定行总和的容量。
从col节点到dest的边缘应具有与给定列总和相等的容量。
从行节点到col节点的边缘应具有根据矩阵中允许值的容量。 (例如,如果矩阵的第x行,第0列的条目必须为零,则将行的容量设置为0,从行节点x到col节点y。)
然后计算从源到目标的最大流量,行节点和列节点之间的流量给出矩阵中的条目。
对于nxn矩阵的解,复杂度为O(n ^ 3)。