data_packing
 
% data_packing.pi (in Picat)
% author:  Mike Bionchik
% date:  06/23/2015
% https://code.google.com/codejam/contest/3014486/dashboard#s=p0
% Round 2 2014
% Problem A. Data Packing
%
% to use: picat data_packing < input_file > output_file
%
% NOTE: slow on large dataset

import cp.

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

do_case(Case) =>
    N = read_int(stdin),
    X = read_int(stdin),
    S = new_map(),

    % read the file sizes into a map to account for duplicates
    foreach (_ in 1..N)
        Size = read_int(stdin),
        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).