找到具有已知行/列总和和最大单元值的矩阵的可能解决方案

问题描述 投票:2回答:2

我试图找到矩阵的解决方案,我知道行和列的总和以及单元格可以具有的最大值。我想找到限制范围内的可能解决方案。我已经尝试了各种各样的事情,比如构建一个所有单元格值的数组,并按顺序从每个单元格中挑选,但无论我尝试什么,我总是遇到问题,我用完了一个单元格的值。我也尝试了一种递归算法但是我只设法得到了第一个结果,或者它没有得到任何解决方案。我想我必须用回溯算法做到这一点?不确定...

任何帮助或指示将不胜感激。

行和A,B,C,列和X,Y,Z以及每个的最大值?众所周知。所有值都是正整数。

    C1 | C2 | C3 
-----------------
R1 | ? | ?  | ? | A
-----------------
R2 | ? | ?  | ? | B
-----------------
R3 | ? | ?  | ? | C
-----------------
     X | Y | Z
arrays algorithm linear-programming subset-sum
2个回答
2
投票

正如您在评论中写道的那样,您希望找到一个自己的解决方案,这里有一些指导原则:

使用Backtrack algorithm找到解决方案。您的价值空间由3 * 3 = 9个独立值组成,每个值都在1maxval[i][j]之间。您的约束将是行和列总和(所有这些都必须匹配)

用所有1s使你的空间充满活力,然后递增它们,直到它们到达maxval。仅在满足该条件的每个值之后评估条件(特别是,在3个值之后,您可以评估第一行,在第6行之后,第7列之后,第二列之后,第二列之后,第三行之后9之后,第三个)

如果你到达第9,在所有条件都过去的情况下,你就有了解决方案。否则尝试从1maxval的值,如果两者都不匹配,退后一步。如果迭代了第一个值,则没有解决方案。

就这样。


更高级的回溯:

您的移动值仅为左上角的2 * 2 = 4值。计算第三列,条件是它必须在1maxval之间,用于该特定元素。在定义[1][1]元素之后,您需要使用列总和来计算[2][2]索引,并通过行总和验证其值(反之亦然)。相同的处理规则适用于上述:迭代所有可能的值,如果没有匹配则返回,并仅在可以应用规则时检查规则。

这是一种更快的方法,因为你有5个绑定变量(底行和右行),只有4个未绑定。这些是您特定规则的优化。但实施起来有点复杂。

PS:使用1是因为你有正整数。如果你有非负整数,你需要从0开始。


4
投票

如果您听说过linear programming(LP)及其“堂兄弟”(ILP,MILP),这可能是一种很好的方法,可以帮助您高效地解决问题。 线性程序包含一组变量(您的矩阵未知数),约束(最大值,行和列的总和),以及目标函数(此处为无)以最小化或最大化。

我们将x [i] [j]称为您要查找的值。有以下数据:

NxM矩阵的维度 max_val[i][j]变量x[i][j]的最大值 row_val[i]i上的值的总和 col_val[j]j上的值的总和

然后一个可能解决您的问题的线性程序是:

// declare variables
int x[N][M] // or eventually float x[N][M] 
// declare constaints
for all i in 1 .. N, j in 1 .. M, x[i][j] <= max_val[i][j]
for all i in 1 .. N, sum[j in 1 .. M](x[i][j]) == row_val[i]
for all j in 1 .. M, sum[i in 1 .. N](x[i][j]) == col_val[j]
// here the objective function is useless, but you still will need one
// for instance, let's minimize the sum of all variables (which is constant, but as I said, the objective function does not have to be useful)
minimize sum[i in 1 .. N](sum[j in 1 .. M](x[i][j]))
// you could also be more explicit about the uselessness of the objective function
// minimize 0

gurobiCplex这样的求解器(但是它们中有更多,例如参见here)可以非常快速地解决这类问题,特别是如果你的解决方案不需要是整数,但可以是浮点数(这会使问题更多,更容易)。它还具有以下优点:不仅执行速度更快,而且编码更快更简单。它们具有几种常见编程语言的API,以方便其使用。 例如,你可以合理地期望在不到一分钟内解决这类问题,在整数情况下有数十万个变量,在实际变量情况下有数百万个。

编辑:在回应评论时,这里是OPL(Cplex和其他LP解算器使用的语言)中的一段代码,可以解决您的问题。我们考虑一个3x3的案例。

// declare your problem input
int row_val[1..3] = [7, 11, 8];
int col_val[1..3] = [14, 6, 6];
int max_val[1..3][1..3] = [[10, 10, 10], [10, 10, 10], [10, 10, 10]];

// declare your decision variables
dvar int x[1..3][1..3];

// objective function
minimize 0;

// constraints
subject to {
    forall(i in 1..3, j in 1..3) x[i][j] <= max_val[i][j];
    forall(i in 1..3) sum(j in 1..3) x[i][j] == row_val[i];
    forall(j in 1..3) sum(i in 1..3) x[i][j] == col_val[j];
}

LP解算器的概念是你只描述你想要解决的问题,然后求解器为你解决它。必须根据一组规则来描述问题。在当前情况下(整数线性规划或ILP),变量必须都是整数,并且约束和目标函数必须是关于决策变量的线性等式(或不等式)。 然后解算器将作为黑盒子工作。它将分析问题,运行可以解决问题的算法,并进行大量优化,并输出解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.