这是一种方法,其中 group 变量已被翻转以保存每个配方的成分(也将其重命名为 ingredients)。现在您可以使用all_disjoint 来制定所选菜肴不得使用相同食材的约束条件。
include "globals.mzn";
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
array[RECIPES] of set of INGREDIENTS: ingredients;
array[1..numDishes] of var RECIPES: selected_menu;
constraint all_disjoint([ingredients[selected_menu[i]] | i in 1..numDishes]);
var int: obj = sum([value[selected_menu[i]] | i in 1..numDishes]);
solve maximize obj;
output ["total value=\(obj)\n"] ++
["selected_menu=\(selected_menu)\n"] ++
["ingredients=\([ingredients[selected_menu[i]] | i in 1..numDishes])\n"];
使用数据运行:
numDishes = 2;
nIngred = 8;
nRecipes = 10;
value = [10,8,4,2,6,9,5,3,8,10];
ingredients = [{1,2,3,4},{2,4,5},{3,4,8},
{1},{6,8},{1,2,3,6},
{2,7},{3,6,7},{5},{5,6,7}];
给予:
total value=20
selected_menu=[10, 1]
ingredients=[5..7, 1..4]
编辑: 新版本允许选择比num_dishes 更少的菜品,如果这样可以提供更好的客观价值。这是通过变量dishes 完成的,该变量表示实际选择的菜肴数量。未使用的菜单将具有 0 的值。
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
set of int: RECIPES0 = 0..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
var 1..numDishes: maxDishes;
array[INGREDIENTS] of set of RECIPES: group;
array[1..numDishes] of var RECIPES0: selected_menu;
constraint forall(i in INGREDIENTS)
(sum(m in selected_menu)(m in group[i]) <= 1);
var int: obj = sum([value[selected_menu[i]] | i in 1..maxDishes]);
solve maximize obj;
output["Value: ", show(obj), "\nRecipe: ", show([selected_menu[d] | d in 1..maxDishes])];
编辑:另一个版本使用一个集合来表示selected_menu。
int: nRecipes;
set of int: RECIPES = 1..nRecipes;
array[RECIPES] of int: value;
int: nIngred;
set of int: INGREDIENTS = 1..nIngred;
int: numDishes;
array[INGREDIENTS] of set of RECIPES: group;
var 1..numDishes: dishes;
var set of RECIPES: selected_menu;
% each ingredients may appear in at most one recipe
constraint forall(i in INGREDIENTS)
(card(selected_menu intersect group[i]) <= 1);
constraint card(selected_menu) <= dishes;
var int: obj = sum([value[m] | m in selected_menu]);
solve maximize obj;
output["Value: ", show(obj), "\nRecipe: ", show(selected_menu)];