Your only task is to simplify the original problem, or to solve it directly when simplification is either unnecessary or impossible; the Recursion Fairy will solve all the simpler subproblems for you, using Methods That Are None Of Your Business…
The Recursion Fairy is the inductive hypothesis.
Would the greedy algorithm work?
Find the highest possible score by comparing:
To make the decision for animal[i]
, let the Recursion Fairy give you the maximum score for the rest of the animals. (No for-loop needed.)
At any point in the recursive problem, the subproblems are CandySwap(i+1, held_candy) and CandySwap(i+1, animals[i]).
We can memoize past results in a 2-dimensional array CS based on the two input values. The first value we can fill in is CS[n+1][1..3] = 0, and from there we can go in descending order with n, n-1, n-2, et cetera.
CandySwapMemo(h):
initialize CS[n, *] to 0 for 0 < * < 4
CS[n,C[n]] <- 1
for i <- (n-1) down to 1:
for j <- 1 to 3:
if C[i]=j:
point <- 1
else:
point <- -1
swap <- point + CS[i+1, C[i]]
skip <- CS[i+1,j]
CS[i,j] <- max(swap, skip)
return CC[1, h]
Time: \(O(n)\), Space: \(O(n)\)
Note: you can make it constant space, since the solution only depends on the previous subproblem
C[1..n] // the types of candy held by each animal
PrevMSC[1..3] // memoization structure for max scores of candy, depending on current candy held
tmp[1..3] // a temporary array for storing max scores of candy
FastMaxScoreCandy(CurrentCandy):
PrevMSC[C[n]] <- 1 // we can get a point in the end if we swap
PrevMSC[all candies except C[n]] <- 0 // or maybe we stick with what we have
from animal <- n-1 down to 1:
for candy <- 1..3:
if candy is C[animal]:
DoSwapScore <- 1 + PrevMSC[C[animal]]
otherwise
DoSwapScore <- -1 + PrevMSC[C[animal]]
DontSwapScore <- PrevMSC[candy]
tmp[candy] <- max(DoSwapScore, DontSwapScore)
copy tmp -> PrevMSC
return PrevMSC[CurrentCandy]
set.seed(4323)
candyTypes <- c("peanut", "heath", "truffle")
n <- 20
animalCandy <- sample(candyTypes, n, replace=TRUE)
maxScore <- function(i, myCandy) { # max score from visiting animals i..n holding myCandy
if(i > n)
return(0)
if(myCandy == animalCandy[i])
swap <- 1 + maxScore(i+1, myCandy)
else
swap <- -1 + maxScore(i+1, animalCandy[i])
same <- maxScore(i+1, myCandy)
return(max(swap, same))
}
FastMaxScore <- function() {
S <- matrix(rep(0, 3*(n+1)), nrow = n+1, ncol = 3)
for(i in n:1) {
currentAnimalCandyNum <- which(candyTypes == animalCandy[i])
# holding peanut: Score goes in S[i, 1]
# holding heath: Score goes in S[i, 2]
# holding truffle: Score goes in S[i, 3]
for(myC in 1:3) {
if(candyTypes[myC] == animalCandy[i])
swap <- 1 + S[i+1,myC]
else
swap <- -1 + S[i+1,currentAnimalCandyNum]
same <- S[i+1, myC]
S[i, myC] <- max(swap, same)
}
}
return(S[1,1])
}
[1] 2
[1] 2
set.seed(4323)
candyTypes <- c("peanut", "heath", "truffle")
n <- 20
animalCandy <- sample(candyTypes, n, replace=TRUE)
FastMaxScore()
[1] 9
user system elapsed
1.833 0.007 1.843
user system elapsed
0 0 0
Table #1 | Table #2 | Table #3 | Table #4 | Table #5 | Table #6 | Table #7 |
---|---|---|---|---|---|---|
Josiah | Andrew | Blake | Claire | Jordan | James | Grace |
John | Trevor | Bri | Jack | Logan | Isaac | Kristen |
Nathan | Kevin | Drake | Levi | Ethan | Graham | Talia |