DEV Community

dev.to staff
dev.to staff

Posted on

4 1

Daily Challenge #105 - High-Sum Matrix Drop

You have a square matrix of unsigned integer values. Say, 5 + 5.
Each row of that matrix contains numbers from 1 to 5 (or to whatever length of the matrix), randomly sorted.

You can move through the matrix only one step at the time - either straight down, left-down or right-down.

Your challenge is to write a code that will start at the middle of the top row, and find the path down with the highest sum.

Example:
For the following matrix, you start in c/0. For this matrix the best path would be: c/0, d/1, d/2, e/3, d/5 which scores 4+4+5+4+5 = 22.

+---+---+---+---+---+---+
|   | a | b | c | d | e |
+---+---+---+---+---+---+
| 0 | 2 | 1 | 4 | 5 | 3 |
+---+---+---+---+---+---+
| 1 | 5 | 2 | 1 | 4 | 3 |
+---+---+---+---+---+---+
| 2 | 1 | 3 | 2 | 5 | 4 |
+---+---+---+---+---+---+
| 3 | 1 | 5 | 2 | 3 | 4 |
+---+---+---+---+---+---+
| 4 | 3 | 2 | 1 | 5 | 4 |
+---+---+---+---+---+---+

Good luck!


This challenge comes from peledzohar here on DEV. Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (5)

Collapse
 
craigmc08 profile image
Craig McIlwrath β€’

I didn't do #90, so I'll put my answer here. This is a really stupid, slow, "just works" algorithm. It checks every single possible path. I guess it's around O(n3)?

(Language is Haskell).

data Move = D | DL | DR deriving (Show) 

type Size = Int
type Row = Int
type Col = Int
type Pos = (Row, Col) 

isInSquare :: Size -> Pos -> Bool
isInSquare n (r, c) = all id
  [ r >= 0
  , r < n
  , c >= 0
  , c < n
  ]

executeMove :: Move -> Pos -> Pos
executeMove D  (r, c) = (r + 1, c) 
executeMove DL (r, c) = (r + 1, c - 1)
executeMove DR (r, c) = (r + 1, c + 1)

validMove :: Size -> Pos -> Move -> Bool
validMove n p m = isInSquare n $ executeMove m p

possibleMoves :: Size -> Pos -> [Move]
possibleMoves n p = filter (validMove n p) [D, DL, DR]

generatePaths :: Size -> Pos -> [[Move]]
generatePaths n p
  | fst p == n - 1 = [[]]
  | otherwise      = possibleMoves n p >>= nextMoves
  where nextMoves :: Move -> [[Move]] 
        nextMoves m = generatePaths n (executeMove m p) >>= \ms -> [m : ms] 

-- Middle spot of an even array is defined as the right middle for simplicity. 
middle n
  | odd n     = n `div` 2
  | otherwise = n `div` 2

access :: [[a]] -> Pos -> a
access xss (r, c) = xss !! r !! c

sumIn :: (Num a) => [[a]] -> Pos -> [Move] -> a 
sumIn xss start path = let ps = scanl (flip executeMove) start path
                       in  sum $ map (access xss) ps 

maxBy :: (Ord b) => (a -> b) -> [a] -> a
maxBy f = foldl1 maxOf 
  where maxOf m x = if (f x > f m) then x else m

bestPath :: (Ord a, Num a) => Size -> [[a]] -> ([Move], a)
bestPath n xss = let start = (0, middle n)
                     paths = generatePaths n start 
                 in  maxBy snd $ zip paths $ map (sumIn xss start) paths
Collapse
 
sardok profile image
sinx β€’

My solution using queue. Should be o(n).


import string

def get_steps(i, j, row, col):
    left = j - 1
    right = j + 1
    down = i + 1

    if down >= row:
        return []

    steps = []
    if left >= 0:
        steps.append((down, left))

    steps.append((down, j))

    if right < col:
        steps.append((down, right))

    return steps

def make_and_fill(row, col, fill):
    ret = []
    for _ in range(row):
        row_ = [fill] * col
        ret.append(row_)

    return ret

def find_max_index(xs):
    max_ = max(xs)
    return xs.index(max_)

def get_path(i, j, backtraces):
    ret = []
    queue = [(i, j)]

    while queue:
        pos = queue.pop(0)
        if pos:
            ret.append(pos)
            i, j = pos
            backtrace = backtraces[i][j]
            queue.append(backtrace)

    ret.reverse()
    ret = [f'{string.ascii_letters[j]}/{i}' for (i, j) in ret]
    return ', '.join(ret)


def solve(xs):
    row, col = len(xs), len(xs[0])
    sums = make_and_fill(row, col, 0)
    sums[0][:] = xs[0]
    backtraces = make_and_fill(row, col, 0)
    queue = [(0, col//2)]

    while queue:
        pos = queue.pop(0)
        i, j = pos
        for step in get_steps(i, j, row, col):
            step_i, step_j = step
            acc = sums[i][j] + xs[step_i][step_j]
            if sums[step_i][step_j] < acc:
                queue.append((step_i, step_j))
                sums[step_i][step_j] = acc
                backtraces[step_i][step_j] = pos

    max_index = find_max_index(sums[-1])
    print(sums[-1][max_index])

    path = get_path(row-1, max_index, backtraces)
    print(path)


if __name__ == '__main__':
    matrix = [
        [2, 1, 4, 5, 3],
        [5, 2, 1, 4, 3],
        [1, 3, 2, 5, 4],
        [1, 5, 2, 3, 4],
        [3, 2, 1, 5, 4],
    ]
    solve(matrix)
Collapse
 
michaeltharrington profile image
Michael Tharrington β€’

Thanks for pointing this out, David! This was a mistake.

Collapse
 
peledzohar profile image
Zohar Peled β€’

Hey guys, Someone got mixed up a bit here. That was the 90# challenge, this one was suppose to be the one I've sent you later, with the bottles... :-)

Collapse
 
michaeltharrington profile image
Michael Tharrington β€’

Ah jeez... my bad here. πŸ€¦β€β™‚οΈ

You are absolutely right, Zohar!

Dev Diairies image

User Feedback & The Pivot That Saved The Project

πŸ”₯ Check out Episode 3 of Dev Diairies, following a successful Hackathon project turned startup.

Watch full video πŸŽ₯

πŸ‘‹ Kindness is contagious

Dive into this thoughtful piece, beloved in the supportive DEV Community. Coders of every background are invited to share and elevate our collective know-how.

A sincere "thank you" can brighten someone's dayβ€”leave your appreciation below!

On DEV, sharing knowledge smooths our journey and tightens our community bonds. Enjoyed this? A quick thank you to the author is hugely appreciated.

Okay