【问题标题】:Minizinc search 2d array with constraintsMinizinc 搜索带约束的二维数组
【发布时间】:2016-01-31 18:21:43
【问题描述】:

如何从二维数组的每一行中选择最小的数字,同时确保同一列最多可以选择两次 (以下情况,第 1 行选择第 5 列;第 2 行选择第 5 列,而第 3 行无法再选择第 5 列,因此选择第 2 列作为最小值): (此外,在 java 中,通常使用 ArrayList 来添加和删除元素,但如何在 Minizinc 中使用约束来做到这一点)?

int: m = 3;
int: n = 5;
array[1..m,1..n] of int: diffs = [|14,18,24,30,13
                                  |10,12,18,24,7
                                  | 8,7,12,18,6|]

【问题讨论】:

    标签: minizinc


    【解决方案1】:

    以下是一种方法,可以最小化所选列的值与每行的“实际”最小值之间的差值之和。

    include "globals.mzn"; 
    int: m = 3;
    int: n = 5;
    array[1..m,1..n] of int: diffs = [|14,18,24,30,13
                                      |10,12,18,24,7
                                      | 8,7,12,18,6|];
    
    % decision variables
    array[1..m] of var 1..n: x; % which row to select
    var int: z; % difference between the selected and smallest values
    
    solve minimize z;
    % solve satisfy;
    
    % constraint 1: at_most 2 of the same column can be selected
    constraint
      % at most two rows can have the same column
      forall(j in 1..n) (
        at_most(2,x,j)
      )
    ; 
    
    % constraint 2: calculate the least difference
    constraint
      % get smallest difference to the smallest value
      z = sum(i in 1..m) (
           % value of selected column - the smallest value of the row
           diffs[i,x[i]]-min([diffs[i,j] | j in 1..n]) 
      )
      % /\ % for solve satisfy
      % z = 1
      ;
    
      output [
        "z: \(z)\n",
        "x: \(x)  values:\([diffs[i,x[i]] | i in 1..m])\n"
      ];
    

    对于这个问题实例,有两个 z=1 的最优解,即解比“真实”最优值(没有最大 2 列约束)大 1。

     z: 1 
     x: [5, 5, 2]  values:[13, 7, 7]
     ----------
     z: 1 
     x: [1, 5, 5]  values:[14, 7, 6]
    

    第一个解决方案意味着我们从第 5 列中为前 2 行选择值(即 13 和 7 的值),对于第三行,我们从第 2 列中选择值(即 7)。这恰好是示例中提到的解决方案。

    还有一种替代方法,将约束 2 替换为以下约束,即直接对所选值求和(而不是与每行最小值的差):

    % constraint 2: calculate the least difference
    constraint
      z = sum([diffs[i,x[i]] | i in 1..m])
      % /\ % for solve satisfy
      % z = 27
    ; 
    

    当然,它具有相同的列解决方案。区别仅在于“z”的值:

    z: 27 
    x: [5, 5, 2]  values:[13, 7, 7]
    ---------
    z: 27 
    x: [1, 5, 5]  values:[14, 7, 6]
    

    可以说后一种变体更简洁,但如果“diffs”矩阵中的值很大,那么可能应该使用第一个变体,因为求解器倾向于更乐于使用较小的值。 (对于具有大值的矩阵,建议使用“z”而不是“var int”的受限域,但我今晚有点懒。:-)

    【讨论】:

    • 很好的解释。但我想知道为什么添加约束 z = 1 会改变求解器对第一个变体的解决方案? - 即x从[1,5,5]变为[5,5,2]?
    • "z=1" 应该与 "solve meet" 一起使用以获得所有最优解。因此,您首先运行“求解最小化 z”以获得“z”的最佳值(此处为 1)。然后添加约束“z=1”并更改为“求解满足”以获得 z = 1 的所有解。
    • 我知道它现在是如何工作的。但是,他们都没有一次性给我两个解决方案 - 而我认为“z = 1”和“解决满足”应该一次性获得所有解决方案......
    • 如果您运行 MiniZincIDE,那么您在配置选项卡中选中“显示所有解决方案”(或“显示 n 个解决方案”)。如果您从命令行运行,请添加“-a”标志(用于显示所有解决方案)。
    猜你喜欢
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    相关资源
    最近更新 更多