【问题标题】:minizinc: find element in arrrayminizinc:在数组中查找元素
【发布时间】:2015-11-18 11:01:18
【问题描述】:

我有两个不同长度的数组(类型:int)。我怎样才能在数组 b 中为数组 a 中的每个数字找到最接近的数字(虽然可能由于语法错误,但以下内容不起作用):

int: m;
int: n;
array [1..m] of int: a;
array [1..n] of int: b;
array[1..m] of int: results;
results = [abs(a[i] - b[j])| i in 1..m, j in 1..n];
solve minimize results;
output ["Solution: ", show(results)];

【问题讨论】:

    标签: minizinc


    【解决方案1】:

    (对于具有尽可能多信息的完整模型总是有帮助的,例如“m”和“n”的值以及其他已知/固定值。此外,提及错误消息通常会有所帮助。)

    你的模型中有几个未知的东西,所以我不得不猜测一下。

    我猜“结果”确实应该是一个单一的决策变量,而不是您定义的数组。然后就可以写了

    var int: results = sum([abs(a[i] - b[j])| i in 1..m, j in 1..n]);
    

    var int: results;
    ...
    constraint results = sum([abs(a[i] - b[j])| i in 1..m, j in 1..n]);
    

    此外,就目前而言,该模型并不是特别有趣,因为它只定义了两个常量数组“a”和“b”(必须用常量值填充)。我假设其中至少有一个是决策变量。决策变量数组必须用“var int”声明(或者更好:类似于“var 1..size”,其中 1..size 是数组中可能值的域)。

    这是一个工作模型的示例,它可能与您的想法相似,也可能不同:

    int: m = 10;
    int: n = 10;
    array [1..m] of int: a = [1,2,3,4,5,6,7,8,9,10];
    array [1..n] of var 1..10: b;
    var int: results = sum([abs(a[i] - b[j])| i in 1..m, j in 1..n]);
    
    solve minimize results;
    output [
      "Solution: ", show(results),"\n",
      "a: ", show(a), "\n",
      "b: ", show(b), "\n",
      ];
    

    2015 年 11 月 19 日更新:

    我不确定我是否完全理解了这些要求,但这里有一个变体。请注意,求和循环根本不使用“b”数组,只使用“a”和“results”。为了确保 "results" 中的值是从 "b" 中选择的,"results" 的域只是 "b" 中的值的集合。

    int: m = 10;
    int: n = 10;
    array [1..m] of int: a = [1,2,3,4,5,6,7,8,9,10];
    array [1..n] of int: b = [5,6,13,14,15,16,17,18,19,20];
    
    % decision variables
    
    % values only from b
    array[1..m] of var {b[i] | i in 1..n}: results;
    var int: z; % to minimize
    
    constraint
       z >= 0 /\
       z = sum(i in 1..m) (
         sum(j in 1..m) (abs(a[i]-results[j])) 
         % (abs(a[i]-results[i])) % alternative interpretation (see below)
       )
    ;
    
    solve minimize z;
    
    output [
      "z: ", show(z), "\n",
      "results: ", show(results),"\n",
      "a: ", show(a), "\n",
      "b: ", show(b), "\n",
    ];
    

    Gecode 有这个最佳解决方案:

     z: 250
     results: [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
     a: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     b: [5, 6, 13, 14, 15, 16, 17, 18, 19, 20]
    

    另一个求解器 (Opturion CPX) 的解决方案与您的变体更相似:

     z: 250
     results: [6, 6, 5, 5, 5, 6, 6, 6, 5, 5]
     a: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     b: [5, 6, 13, 14, 15, 16, 17, 18, 19, 20]
    

    请注意,两种解决方案的最佳目标值(“z”)相同,均为 250。

    但是,对要求有另一种解释(来自您的评论):

    对于a中的每个元素,从b中选择一个对应的值 - this value 必须与 a 中的每个元素的值最接近。

    "results" 中的每个值只对应于 "a" 中具有相同索引 ("i") 的值,即

     % ...
     constraint
       z >= 0 /\
       z = sum(i in 1..m) (
          (abs(a[i]-results[i])) 
       )
    
     ;
    

    那么解决方案是(Gecode):

    z: 19
    results: [5, 5, 5, 5, 5, 6, 6, 6, 6, 13]
    a: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    b: [5, 6, 13, 14, 15, 16, 17, 18, 19, 20]
    

    然后选择“结果”中的最后一个值 (13),因为它更接近 10(“a”中的最后一个元素)。

    更新 2 (2015-11-20)

    关于第二条评论,关于 2D(不是您编写的 3D 版本),这是一个模型。它基于上述模型的第二种解释。将其扩展到更大的维度只是改变维度和添加循环变量的问题。

    请注意,这假设 - 可能与您最初的问题相反 - “a”和“results”的维度是相同的。如果不是,则第二种解释不可能是您想要的。此外,我更改了“a”和“b”中的值以使其更有趣。 :-)

    int: m = 3;
    int: n = 3;
    array [1..m,1..n] of int: a = [|1,2,3|4,5,6|7,8,9|];
    array [1..m,1..n] of int: b = [|5,6,13|14,15,16,|7,18,19|];
    
    % decision variables
    
    % values only from b
    array[1..m,1..n] of var {b[i,j] | i in 1..m, j in 1..n}: results;
    var int: z;
    
    constraint
       z >= 0 /\
       z = sum(i in 1..m, j in 1..n) (
         (abs(a[i,j]-results[i,j]))
      )
    ;
    
    solve minimize z;
    
    output [  "z: ", show(z), "\n" ]
    ++["results:"]++
    [
      if j = 1 then "\n" else " " endif ++
        show_int(2,results[i,j])
      | i in 1..m, j in 1..n
    ]
    ++["\na:"]++
    [
       if j = 1 then "\n" else " " endif ++
          show_int(2,a[i,j])
       | i in 1..m, j in 1..n
    ]
    ++["\nb:"]++
    [
       if j = 1 then "\n" else " " endif ++
         show_int(2,b[i,j])
        | i in 1..m, j in 1..n
    ];
    

    一个最佳解决方案是这样的:

    z: 13
    
    results:
     5  5  5
     5  5  6
     7  7  7
    
    a:
     1  2  3
     4  5  6
     7  8  9
    
    b:
     5  6 13
    14 15 16
     7 18 19
    

    【讨论】:

    • 更多信息(a, b 是固定数组,而 results 是 a 大小的数组,由程序填充):例如:array [1..m] of int: a = [1,2,3,4,5,6,7,8,9,10]; int 数组 [1..n]:b = [5,6,13,14,15,16,17,18,19,20];约束:对于 a 中的每个元素,从 b 中选择一个对应的值 - 该值必须与 a 中的每个元素的值最接近 - 所以结果将是 [5,5,5,5,5,6,6, 6,6,6]
    • 第二种解释确实解决了我的问题。超清晰的答案!但是,我仍然想问如果所有数组都是 3-d 怎么办 - 从某种意义上说,数组中的每个元素都将具有三个值: [|1, 1, 1|2, 2, 2 |3, 3, 3 |] - 仍然可以进行这样的搜索吗?
    • 我(仍然)不确定我是否完全理解您的意思,但我用 2D 变体更新了答案(不是 3D,因为您的示例只是一个 2D 矩阵)。
    • 你的回答真的很有帮助! :) 顺便说一句,我还想知道您是否知道如何从 Java 程序中调用 Minizinc 模型,并将数组作为传递参数?有什么特殊的命令可以做到这一点吗? :)
    • 您在 stackoverflow.com/questions/33815339/… 中提出了同样的问题。我想知道你的意思更准确。请在那里回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2014-05-21
    • 2016-05-14
    • 2016-11-11
    • 2017-04-10
    相关资源
    最近更新 更多