56 lines
2.5 KiB
MiniZinc
56 lines
2.5 KiB
MiniZinc
int: m; % number of people
|
|
set of int: PERSON = 1..m;
|
|
int: n; % number of goods
|
|
set of int: GOOD = 1..n;
|
|
array[GOOD] of int: available; % number of each good available
|
|
array[GOOD] of int: value;
|
|
array[PERSON] of int: npref; % number of preferences for each person
|
|
int: tpref = sum(npref);
|
|
set of int: PREF = 1..tpref;
|
|
array[PREF] of GOOD: good_pref; % good for each preference
|
|
array[PREF] of int: req_pref; % number required for each preference
|
|
|
|
int: maxreq = max(req_pref);
|
|
array[PERSON] of var GOOD: good;
|
|
array[PERSON] of var 0..maxreq: num;
|
|
|
|
array[PERSON] of int: cumpref = [ sum(p2 in PERSON where p2 < p)(npref[p2]) | p in PERSON ];
|
|
function GOOD: pref(PERSON: p, int: i) = good_pref[cumpref[p] + i];
|
|
function int: req(PERSON: p, int: i) = req_pref[cumpref[p] + i];
|
|
|
|
|
|
array[PERSON,GOOD] of 0..n: rank = array2d(PERSON,GOOD,
|
|
[ max([ (pref(p,i) = g)*i | i in 1..npref[p] ]) | p in PERSON, g in GOOD ]);
|
|
array[PERSON,GOOD] of 0..maxreq: required = array2d(PERSON,GOOD,
|
|
[ max([ (pref(p,i) = g)*req(p,i) | i in 1..npref[p] ]) | p in PERSON, g in GOOD ]);
|
|
|
|
|
|
% choose one preference for each person
|
|
array[PERSON] of var 1..max(npref): preference;
|
|
constraint forall(p in PERSON)(preference[p] <= npref[p]);
|
|
constraint forall(p in PERSON)(good[p] = good_pref[cumpref[p] + preference[p]]);
|
|
constraint forall(p in PERSON)(num[p] = req_pref[cumpref[p] + preference[p]]);
|
|
|
|
% ensure enough goods for each assignment, and calculate remainder
|
|
array[GOOD] of var 0..max(available): remainder;
|
|
constraint forall(g in GOOD)
|
|
(sum(p in PERSON)((good[p] = g)*num[p]) + remainder[g]= available[g]);
|
|
|
|
% ensure the assignment is stable
|
|
constraint forall(p1,p2 in PERSON where p1 < p2)
|
|
( rank[p1,good[p1]] < rank[p1,good[p2]] \/ rank[p1,good[p2]] = 0 \/
|
|
rank[p2,good[p2]] < rank[p2,good[p1]] \/ rank[p2,good[p1]] = 0 \/
|
|
required[p1,good[p2]] - required[p2,good[p2]] > remainder[good[p2]] \/
|
|
required[p2,good[p1]] - required[p1,good[p1]] > remainder[good[p1]]);
|
|
var int: objective = sum(g in GOOD)(remainder[g]*value[g]);
|
|
solve :: int_search(preference, first_fail, indomain_min)
|
|
maximize objective;
|
|
|
|
var int: obj = sum(p in PERSON)(num[p]*value[good[p]]);
|
|
|
|
output ["objective = \(objective);\n"];
|
|
output ["obj = \(obj);\n"];
|
|
output ["good = \(good);\n"];
|
|
output ["num = \(num);\n"];
|
|
output ["preference = \(preference);\n"];
|