Category: Miscellaneous
Author/Contact Info Randal L. Schwartz (merlyn)
Description: Ovid recently posed a puzzle about how to minimize the text in an HTML table. While many solutions had been posed, I kinda like the way I finally solved it while sitting in a recent meeting of the group when I should have been listening to chromatic give his talk.

use List::Util qw(sum max);

use Memoize;

my @height = qw/ 10 15 25 30 10 13 /;
my $cols = 4;

my ($maxheight, @cols) = make_cols($cols, @height);

print "max height is $maxheight\n";
print join(" ", map "[@$_]", @cols), "\n";

sub make_cols {
  my ($cols, @height) = @_;
  my $warnmsg = "computing for $cols cols with @height =>";

  ## non-recursive case:
  if ($cols <= 1) {
    warn "$warnmsg returning trivial [@height]\n";
    return sum(@height), [@height] if $cols <= 1;

  ## oops, work to do.  Search for a pivot.
  ## first, get a trial solution:

  my @leftcol = shift @height;
  my ($rightmax, @rightcols) = make_cols($cols-1, @height);
  my @best = (max(sum(@leftcol), $rightmax), [@leftcol], @rightcols);

  ## now iterate until we are producing worse solutions:
  while (@height > $cols - 1) {
    push @leftcol, shift @height;
    my ($rightmax, @rightcols) = make_cols($cols-1, @height);
    my @try = (max(sum(@leftcol), $rightmax), [@leftcol], @rightcols);
    next if $try[0] >= $best[0]; # that's worse
    @best = @try;

  warn "$warnmsg returning", map(" [@$_]", @best[1..$#best]), "\n";
  return @best;