获取动态子矩阵并应用约束

Get dynamic submatrix and apply constraints

我是约束编程的新手,我正在尝试解决一个问题,我需要从一个由数字组成的二维数组中获取尽可能少的子数组 (2D),并尽可能多地覆盖尽可能的原始二维数组,遵守以下规则:

例如以下矩阵:

3 5 1 4
5 1 2 8
0 8 1 3
8 3 2 1

对于 10 的最大和,解决方案是:

 3 -not picked 
{ 5 1 4 }
{ 5 1 }
{ 2 8 }
{ 0 8 }
{ 1 3 
  2 1 }
 8 -not picked

现在我正在使用 diffn() equivalent of or-tools (MakeNonOverlappingBoxesConstraint()) 创建将覆盖原始数组的矩形。

我的问题是如何获取 diffn() 创建的矩形并根据每个矩形的位置和大小拆分原始矩阵,这样我就可以应用 Sum 约束.

如果有另一种方法可以在不使用 diffn() 的情况下实现相同的约束,那么我会尝试一下,但我想不出任何其他方法。

谢谢!

在求解器内部,从基于 IntVar 的数组中获取值的方法是使用它的 MakeElement() function and in this case the 2d version

这样您就可以从矩阵中获取特定值,但不能获取基于两个 IntVar 的范围(例如矩形的 x - dx)。要完成范围部分,您可以使用循环和 ConditionalExpression() 来确定指定值是否在范围内。

例如,在一维数组中,为了从 data 获取元素,位置 xx + dx 将如下所示

int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IntVar x = solver.MakeIntVar(0, data.Length - 1);
IntVar dx = solver.MakeIntVar(1, data.Length);

solver.Add(x + dx <= data.Length);

IntVarVector range = new IntVarVector();
for (int i = 0; i < dx.Max(); i++)
{
    range.Add(solver.MakeConditionalExpression((x + i < x + dx).Var() , solver.MakeElement(data, (x + i).Var()), 0).Var());
}

solver.Add(range.ToArray().Sum() <= 10);

如果是二维数组(如问题中所示),那么您只需遍历两个维度。唯一的区别是 MakeElement() 的 2d 版本接受一个 IndexEvaluator2 项目(C# 中的 LongLongToLong)所以你必须自己制作继承 LongLongToLong 的 class并覆盖 Run() 函数。

class DataValues: LongLongToLong
{
    private int[,] _data;
    private int _rows;
    private int _cols;

    public DataValues(int[,] data, int rows, int cols)
    {
        _rows = rows;
        _cols = cols;
        _data = data;
    }

    public override long Run(long arg0, long arg1)
    {
        if (arg0 >= _rows || arg1 >= _cols)
            return 0;

        return _data[arg0, arg1];
    }
}

这个 class 的唯一问题是它可以从数组中请求一个值,所以我们必须自己用 if (arg0 >= _rows || arg1 >= _cols) 来处理它。

P.S。我不知道这是否是完成它的最佳方法,但这是我能想到的最好方法,因为我在网上找不到类似的方法。