Remove the mininum sum seam from an array
Haskell, 187 bytes
l=length
f a@(b:c)=snd$maximum$(zip=<<map(sum.concat))$map(zipWith((uncurry((.drop 1).(++)).).flip splitAt)a)$iterate((\e@(f:_)->[f-1:e,f:e,min(f+1)(l b-1):e])=<<)[[y]|y<-[0..l b-1]]!!l c
Usage example:
*Main> f [[1,4,3,5,2],[3,2,5,2,3],[5,2,4,2,1]]
[[4,3,5,2],[3,5,2,3],[5,4,2,1]]
*Main> f [[1],[2],[3]]
[[],[],[]]
*Main> f [[1,2,3,4,5]]
[[2,3,4,5]]
How it works, short version: build a list of all paths (1), per path: remove corresponding elements (2) and sum all remaining elements (3). Take the rectangle with the largest sum (4).
Longer version:
Input parameters, assigned via pattern matching:
a = whole input, e.g. [[1,2,4],[2,5,6],[3,1,6]]
b = first line, e.g. [1,2,4]
c = all lines, except first, e.g. [[2,5,6],[3,1,6]]
Step (1), build all paths:
iterate((\e@(f:_)->[f-1:e,f:e,min(f+1)(l b-1):e])=<<)[[y]|y<-[0..l b-1]]!!l c
[[y]|y<-[0..l b-1]] # build a list of single element lists
# for all numbers from 0 to length b - 1
# e.g. [[0],[1],[2]] for a 3 column input.
# These are all possible start points
\e@(f:_)->[f-1:e,f:e,min(f+1)(l b-1):e]
# expand a list of paths by replacing each
# path with 3 new paths (up-left, up, up-right)
(...)=<< # flatten the list of 3-new-path lists into
# a single list
iterate (...) [...] !! l c # repeatedly apply the expand function to
# the start list, all in all (length c) times.
Step (2), remove elements
map(zipWith((uncurry((.drop 1).(++)).).flip splitAt)a)
(uncurry((.drop 1).(++)).).flip splitAt
# point-free version of a function that removes
# an element at index i from a list by
# splitting it at index i, and joining the
# first part with the tail of the second part
map (zipWith (...) a) $ ... # per path: zip the input list and the path with
# the remove-at-index function. Now we have a list
# of rectangles, each with a path removed
Step (3), sum remaining elements
zip=<<map(sum.concat) # per rectangle: build a pair (s, rectangle)
# where s is the sum of all elements
Step (4), take maximum
snd$maximum # find maximum and remove the sum part from the
# pair, again.
CJam, 51 44 bytes
{_z,1$,m*{_1>.-W<2f/0-!},{1$.=:+}$0=.{WtW-}}
This is an anonymous function that pops a 2D array from the stack and pushes one in return.
Try the test cases online in the CJam interpreter.1
Idea
This approach iterates over all possible combinations of row elements, filters out those that do not correspond to seams, sorts by the corresponding sum, select the minimum and removes the corresponding elements from the array.2
Code
_z, e# Get the length of the transposed array. Pushes the number of columns (m).
1$, e# Get the length of the array itself. Pushes the number of rows (n).
m* e# Cartesian power. Pushes the array of all n-tuples with elements in [0 ... m-1].
{ e# Filter:
_1> e# Push a copy of the tuple with first element removed.
.- e# Vectorized difference.
W< e# Discard last element.
2f/ e# Divide all by 2.
0- e# Remove 0 from the results.
! e# Push 1 if the remainder is empty and 0 otherwise.
}, e# Keep only tuples which pushed a 1.
e# The filtered array now contains only tuples that encode valid paths of indexes.
{ e# Sort by:
1$ e# Copy the input array.
.= e# Retrieve the element of each row that corresponds to the index in the tuple.
:+ e# Add all elements.
}$ e#
0= e# Retrieve the tuple of indexes with minimum sum.
.{ e# For each row in the array and the corresponding index in the tuple:
Wt e# Replace the element at that index with -1.
W- e# Remove -1 from the row.
}
1 Note that CJam cannot distinguish between empty arrays and empty strings, since strings are just arrays whose elements are characters. Thus, the string representation of both empty arrays and empty strings is ""
.
2 While the time complexity of the algorithm shown on the Wikipedia page should be of O(nm) for an n×m matrix, this one's is at least of O(mn).
IDL 8.3, 307 bytes
Meh, I'm sure this won't win because it's long, but here's a straightforward solution:
pro s,a
z=size(a,/d)
if z[0]lt 2then return
e=a
d=a*0
u=max(a)+1
for i=0,z[1]-2 do begin
e[*,i+1]+=min([[u,e[0:-2,i]],[e[*,i]],[e[1:*,i],u]],l,d=2)
d[*,i]=l/z[0]-1
endfor
v=min(e[*,-1],l)
r=intarr(z[1])+l
for i=z[1]-2,0,-1 do r[0:i]+=d[r[i+1],i]
r+=[0:z[1]-1]*z[0]
remove,r,a
print,reform(a,z[0]-1,z[1])
end
Ungolfed:
pro seam, array
z=size(array, /dimensions)
if z[0] lt 2 then return
energy = array
ind = array * 0
null = max(array) + 1
for i=0, z[1]-2 do begin
energy[*, i+1] += min([[null, energy[0:-2,i]], [energy[*,i]], [energy[1:*,i], null]], loc ,dimension=2)
ind[*, i] = loc / z[0] - 1
endfor
void = min(energy[*,-1], loc)
rem = intarr(z[1]) + loc
for i=z[1]-2, 0, -1 do rem[0:i] += ind[rem[i+1], i]
rem += [0:z[1]-1]*z[0]
remove, rem, array
print, reform(array, z[0]-1, z[1])
end
We iteratively create the energy array and track which direction the seam goes, then construct a removal list once we know the final position. Remove the seam via 1D indexing, then reform back into the array with the new dimensions.