data_packing
``` ```
% data_packing.pi (in Picat)
% author:  Mike Bionchik
% date:  06/23/2015
% Round 2 2014
% Problem A. Data Packing
%
% to use: picat data_packing < input_file > output_file
%
% NOTE: slow on large dataset

import cp.

main =>
foreach(I in 1..T)
do_case(I)
end.

do_case(Case) =>
S = new_map(),

% read the file sizes into a map to account for duplicates
foreach (_ in 1..N)
if S.has_key(Size) then
S.put(Size, S.get(Size)+1)
else
S.put(Size, 1)
end
end,

S.put(0, -1),   % 0 has a special meaning - we have `infinite' files with
% size 0 for convenience

% count pairs that will take maximum allowed space
PairCount = 0,
while (find_max_pair(S, X, A, B))
PairCount := PairCount + 1,
S.put(A, S.get(A)-1),
S.put(B, S.get(B)-1)
end,

writef("Case #%w: %w%n", Case, PairCount).

find_max_pair(S, X, A, B) =>
Vars = [A,B],
AllFileSizes = [V : V in S.keys(), S.get(V) > 0],
AllFileSizes != [],
DupFileSizes = [V : V in S.keys(), S.get(V) > 1],
A :: [0|AllFileSizes].sort(),
B :: AllFileSizes.sort_down(),
A #= B #=> B :: DupFileSizes, % if File A = File B, then there must be a
% duplicate
A + B #<= X,
solve([\$max(A+B), rand], Vars).
``````