I understand that this is more of a problem solving than a coding question as such, so my apologies if this post breaks any rules here, but does anyone have any idea how best to go about this?
I am trying to solve the problem, but there is a logical error in my code, or rather I have not considered all the conditions, tell me how to find it.
The problem: An adventurer found himself in a dungeon full of treasures. However, before entering he activated a trap, which in t minutes will flood the entire room. You are given an array of chests, where chests[i] is the number of treasures in the chest. The explorer can either pick up treasure i, taking one minute, or move to the next chest (i 1), which also takes one minute. He starts at position zero, it is not necessary to reach the end of the array.
Determine the maximum amount of treasure the hero can collect. by writing function getResult(chests,t):Integer Input: chests - number of treasures in chests, 2<length(chests)<20, 0<chests[i]<100 t - number of minutes to flood, 0<t<20
Output: Integer - maximum number of treasures collected
Example 1: chests = [1, 4, 2] t = 3 getResult(chests, t) = 5 // In the first minute the hero collected treasure from the first chest, in the second minute, he moved to the next chest, in the third minute, he gets the treasure from it
Example 2: chests = [7, 8, 9] t = 2 getResult(chests, t) = 8 // In the first minute, the hero goes to the second chest and gets the treasure from it, than taking the treasure in the first chest
below are my reasons, and code.
the horizontal side of the matrix is moves and captures. They don't differ, because it takes the same amount of time to move or capture an item. 1 unit per move or capture. The chests are arranged vertically, in order of increasing number of moves to the chest, so we can say If n (number of chests)=4, the values in the chests are in order of distance of moves with the contents of 1, 4, 3, 5 It is possible to take any[j,i] chest in i moves. In 10 moves it is possible to take all items, the point is that the number of moves n for taking chest is a triangular number, i.e. the sum of the first n natural numbers. The formula for calculating a triangular number is: 1/2 * n * (n 1) We build a matrix, put the inputs [1, 4, 3, 5] there, and place all the sums of those there, too, as chests. If one cell of the matrix contains more than 1 chest, we choose maximum. all combinations without regard to direction, (i.e. 2 3=3 2 without regard to such permutations) summary matrix: chests and their combinations and steps to get
1__2__3__4__5__6__7__8__9_10
first chest 1, | | | | | | | | |
second chest 0, 4, 5 | | | | | | |
third chest 0, 0, 3, 4, 7, 8, | | | |
fourth chest 0, 0, 0, 5, 6, 9,10, 9 12 13
there are combinations not included in the matrix, i.e. 4c 1c,2c>4c 3 (throw out the equal in moves option 4 3 chest, this is not the maximum)
So, form a one-dimensional array to select the best (maximal) combinations for each move
maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13] count sum of elements up to t-1 compare with the element with the number t ANSWER: sumofchests(0,t-1)>maxs_in_onerow(t) ? return sumofchests(0,t-1) : maxs_in_onerow(t) // fill in the backpack, output the result
function getResult(chests, t) {
function transpose(a) { //helper func
// Calculate the width and height of the Array
let w = a.length || 0;
let h = a[0] instanceof Array ? a[0].length : 0;
// In case it is a zero matrix, no transpose routine needed.
if(h === 0 || w === 0) { return []; }
let i, j, t = [];
// Loop through every item in the outer array (height)
for(i=0; i<h; i ) {
// Insert a new row (array)
t[i] = [];
// Loop through every item per item in outer array (width)
for(j=0; j<w; j ) {
// Save transposed data.
t[i][j] = a[j][i];
}
}
return t;
}
function sumofsteps(c = chests) {
if (!Array.isArray(c)) c=Array.from({length:c})
return (c.length * (c.length 1)) / 2;
}
function sumofchests(c = chests) {
return c.reduce((partialSum, a) => partialSum a, 0);
}
const J = sumofsteps(chests);
const I = (chests.length);
// console.log(`${chests.length}, ${J}, ${I}`);
//create a matrix with the size of the number of chests
//for as many moves as it takes to get all the chests=J
let matrix = Array.from({ length: I }, () => new Array(J).fill(0));
let maxs_in_onerow = [];
// fill with values
let prevstepI = 0;
chests.forEach((element,index) => {
let cchests=chests.slice(0,index)
//the side of the matrix, the moves for moving and taking chests, grows like half a square
for (let i = prevstepI; i <=cchests.length; i ) {
// matrix side, chests,
// nothing before the diagonal, skip
if (i<index) continue
if (i===index) { //diagonal, minimum moves to take
prevstepI=i
matrix[index][i]=element
}
let _x=0
while (_x<i) {
matrix[_x].forEach((el , ind ) => { /* ... */
if (el > 0) {matrix[index][i ind 1]=element el}
})
//create combinations of chests
_x =1
if (_x===i) break
}
}
});
// form maxs_in_onerow=[1,4,5,5,7,9,10,9,12,13]
let jmartix=[]
jmartix=transpose(matrix)
for (let j = 0; j < J; j ) {
let cur=Math.max.apply(null, jmartix[j])
maxs_in_onerow.push(cur);
}
// fill in the backpack, output the result
let res;
if (t === 1) res = chests[0];
if (t >= J) res = sumofchests(chests);
if (t<J) {
let res1=Math.max.apply(null,maxs_in_onerow.slice(0,t))
let res2=sumofchests(maxs_in_onerow.slice(0,t-1))
res = res1>res2 ? res1 : res2
}
// console.log( `${matrix}, ${totalsteps()}, t: ${t}, maxs: ${maxs_in_onerow}, res: ${res} ` );
return res;
}
console.log(` input: [1, 4, 2], 3 \n response: ${getResult([1, 4, 2], 3)}`);
console.log(` input: [7, 8, 9], 2 \n response: ${getResult([7, 8, 9], 2)}`);
CodePudding user response:
My sleep-deprived brain is not up trying to interpret your code or your reasoning. Instead, here's a simple recursive solution:
const maxTreasure = ([c, ...cs], t) =>
t <= 0 || c == undefined
? 0
: c == 0
? maxTreasure (cs, t - 1)
: Math. max (c maxTreasure ([0, ...cs], t - 1), maxTreasure (cs, t - 1) )
console .log (`maxTreasure ([1, 4, 2], 3) //=> ${maxTreasure ([1, 4, 2], 3)}`);
console .log (`maxTreasure ([7, 8, 9], 2) //=> ${maxTreasure ([7, 8, 9], 2)}`);
We check whether the time has run out or if there are no more chests found, and if so, simply return 0. If the first chest is empty, we have no reasonable alternative than to move on to the next one, so we reduce the time by one and recur with the remaining chests. Otherwise we have to choose the better of two possibilities: taking the current chests' treasures or moving on to the next one. We use Math .max
to select one of these, and calculate them by recursion. In one case, we include the current chest (c
) and recur with a list of chests that replaces the current chest's value with zero. In the other, we move on to the remaining chests. In either case, we reduce the time by one.
So we have base cases, and three potential recursive calls. In each of those calls, we're reducing the time by 1, so we will eventually reach the case t <= 0
.
That same foggy brains isn't going to do the analysis of time complexity here. I wouldn't be surprised if this is horribly inefficient; it's likely of exponential complexity in the number of chests. But it's simple and a good start at thinking of the problem logically. If it turns out too inefficient for real world use (ha!) we can come back at a solution using bottom-up dynamic programming... and that may be what you're attempting.
But I would always start simply, and often recursion is simplest.