Max skyline

Here's another problem well-suited for J/APL through which I studied point-free programming. Imagine a 4x4 city block of buildings, some much taller than their peers. Their positions and heights could be represented by the following matrix.

   M =: 4 4 $ 3 0 8 4 2 4 5 7 9 2 6 3 0 3 1 0

   M

3 0 8 4
2 4 5 7
9 2 6 3
0 3 1 0

If we were to view the skyline of this block from the north or south, the tallest buildings spanning the horizon would look like the following graph.

top-down skyline

Viewing the block from the east of west would yield a different skyline.

left-right skyline

Assuming these skylines are iconic and need to be preserved, what is the maximum number of stories that can be added to the other buildings in the block without altering either of these views?

The solution to the problem is quite simple; it hinges on matrix transposition. Both the north/south and east/west skylines can be taken into account by comparing the block matrix against its own transposed form.

Start off with a hook that compares M against its transposition, taking the lower value at each index.

   (<.|:) M

3 0 8 0
0 4 2 3
8 2 6 1
0 3 1 0

Then take the greatest value in each row of this matrix. This results in a vector of maximum heights that will not upset either skyline.

   >./&(<.|:) M

8 4 8 3

Each of these greatest values in the vector are then mapped across their respective rows in the original M, subtracting My,x from the maxy. This looks like the following.

8 - 3 0 8 4
4 - 2 4 5 7
8 - 9 2 6 3
3 - 0 3 1 0

This operation can be accomplished by composing the previous function train against a subtraction operation with flipped parameters.

   (-~>./&(<.|:)) M

 5 8  0  4
 2 0 _1 _3
_1 6  2  5
 3 0  2  3

The negative values look weird here, but they'll be smoothed out in the final sum. That is just two addition reducers over the matrix.

   +/+/(-~>./&(<.|:)) M
35

A total of 35 stories can be added to the city block.