The main trick of this problem was to realize that the ordering of the items in the tallest tower is known: it is always possible to build a tallest tower where the sum of the weight and strength of an item is increasing from the top to the bottom.
Assume that item1 with weight W1 and strength S1 is on top of item2 with weight W2 and strength S2 and the top of the tower above item1 weights W0.
. . . . | W0 | |-----| |S1,W1| |-----| |S2,W2| |-----| . .then if the two items are in the wrong order, ie.
S2+W2 < S1+W1then from the constraints of the problem
W0+W1 <= S2and thus
W0+W1+W2 < S1+W1which means item1 is strong enough to hold item2 and the top of the tower:
W0+W2 < S1so indeed the two items can be exchanged so the sum of strength and weight is increasing from the top to the bottom.
With the ordering in mind it is possible to search for optimal towers increasing the item set one by one: sort the intems by S+W and find the lightest tower for any given height using the first few items (building the tower from the top).
With pseudocode:
// H[i],W[i],S[i] are the height,weight,strenght of item i // Name[i] is the index string of item i before sorting // tower[h] gives the items of the optimal tower of height h tower[0] = "" // Wtower[h] is the weight of the lightest tower of height h Wtower[0] = 0 Wtower[1..] = infinity Hmax = 0 for (i = 0; i < N; i++) { // try to add item i at the bottom of each tower we have so far for (h = Hmax; h >= 0; h--) { if (Wtower[h] > S[i]) { continue } Hnew = h + H[i] if (Wtower[Hnew] > Wtower[h] + W[i]) { Wtower[Hnew] = Wtower[h] + W[i] tower[Hnew] = tower[h] + " " + Name[i] if (Hmax < Hnew) Hmax = Hnew } } } print Hmax print tower[Hmax]
The described approach can solve small inputs, but for large inputs it takes a lot of memory to keep all the items of the best tower for all heights around. Optimal towers often share a chain of items (eg. the top few items are the same in several optimal towers) so instead of keeping distinct lists towers can be represented using linked lists sharing references. When a tower is updated the old unused list items should be freed to have enough memory, this can be done with various garbage collector techniques, but probably reference counting is the simplest solution.
If the chains still don't fit into memory a further improvement is to find the optimal tower iteratively: if only the maximum height of the tower is the question then the DP does not need much memory, the same is true if we only care about the last few items (items at the bottom). So space can be traded for time by only keeping the last few items of the optimal tower determining the items at the bottom and then starting over from scratch with a smaller item set.