Open In App

Furthest Reachable Tower using Blocks and Ladders

Last Updated : 26 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array heights[] of size N, where heights[i] is the height of the ith tower. We are standing at the 0th tower with B blocks and L ladders and we have to reach the furthest tower possible by jumping on adjacent towers. For ith tower,

  • If heights[i + 1] <= heights[i], then we can simply jump to the next tower. Else,
  • If heights[i + 1] > heights[i], then we can either use a single ladder or use (heights[i + 1] – heights[i]) blocks to jump to the next tower.

Find the farthest tower we can reach using at most B blocks and L ladders.

Note: A Ladder or Block once used cannot be used again.

Examples:

Input: N=9, heights = [4, 12, 2, 7, 3, 18, 20, 3, 19], B= 10, L= 2
Output: 7
Explanation:

  • Start at tower 0.
  • Move to tower 1 using your first ladder since 4 < 12.
  • Move to tower 2 without using blocks nor ladders because 12 > 2.
  • Move to tower 3 using 5 blocks since 2 <= 7.
  • Move to tower 4 without using ladders nor blocks since 7 >= 3.
  • Move to tower 5 using your second ladder because 3 < 18.
  • Move to tower 6 using 2 blocks because 18 < 20.
  • Move to tower 7 without using blocks nor ladders because 20 > 3.
  • It is impossible to go beyond tower 7 because you do not have any more sufficient blocks or ladders.

Input: N=7, heights = [4, 2, 7, 6, 9, 14, 12], B= 5, L = 1
Output: 4
Explanation:

  • Starting at tower 0.
  • Go to tower 1 without using ladders nor blocks since 4 >= 2.
  • Go to tower 2 using 5 blocks. You must use either blocks or ladders because 2 < 7.
  • Go to tower 3 without using ladders nor blocks since 7 >= 6.
  • Go to tower 4 using your only ladder. You must use either blocks or ladders because 6 < 9.

It is impossible to go beyond tower 4 because you do not have any more blocks or ladders.

Algorithm: The problem can be solved using the following algorithm:

The problem can be solved using Greedy Approach. Initially, use blocks to climb up the towers. When we run out of blocks, if the find the maximum difference of heights where we have used blocks and then use a ladder for that distance to get extra blocks. To keep track of how many blocks we’ve used at each step, we use a priority queue to store the differences of heights where we have used blocks.

To simplify things, we ensure that we always have enough blocks by continuously using ladder instead of blocks for the largest jump encountered so far. If, at any point, we don’t have enough blocks, we use a ladder and adjust accordingly.

Steps to solve the problem:

  • Start from the 0th tower and use blocks to jump to the next towers till all the blocks have been used.
  • After using all the blocks, if we need more blocks then see the maximum jump which we have taken using blocks and cover that maximum jump using a ladder to get extra blocks.
  • Maintain max heap to store the differences which we have covered using blocks and pop from the max heap after using all the blocks.
  • If at any tower, we have used all the blocks and ladders break and return the answer.

Implementation:

C++
#include &lt;bits/stdc++.h&gt;
using namespace std;

int main()
{
    // Input
    int N = 9, B = 10, L = 2;
    int heights[] = { 4, 12, 2, 7, 3, 18, 20, 3, 19 };

    // max heap to store difference between two adjacent
    // towers which we have covered using blocks
    priority_queue&lt;int&gt; maxB;
    int currentTower = 0;

    while (currentTower &lt; N - 1) {
        // Calculate the difference between the current
        // tower and the next tower
        int diff = heights[currentTower + 1]
                   - heights[currentTower];

        if (diff &gt; 0) {
            B -= diff;
            // Use blocks to cover the difference between
            // the current and the next tower
            maxB.push(diff);

            // If all the blocks are used, start using
            // ladders
            if (B &lt; 0) {
                B += maxB.top();
                maxB.pop();
                L--;
            }

            // If all the ladders and blocks are used, break
            if (L &lt; 0)
                break;
        }
        currentTower++;
    }

    cout &lt;&lt; currentTower;
    return 0;
}
Java
/*code by Flutterfly*/
import java.util.PriorityQueue;

public class TowerBuilding {
    public static void main(String[] args) {
        // Input
        int N = 9, B = 10, L = 2;
        int[] heights = {4, 12, 2, 7, 3, 18, 20, 3, 19};

        // Max heap to store the difference between two adjacent
        // towers, which we have covered using blocks
        PriorityQueue<Integer> maxB = new PriorityQueue<>((a, b) -> b - a);
        int currentTower = 0;

        while (currentTower < N - 1) {
            // Calculate the difference between the current
            // tower and the next tower
            int diff = heights[currentTower + 1] - heights[currentTower];

            if (diff > 0) {
                B -= diff;
                // Use blocks to cover the difference between
                // the current and the next tower
                maxB.add(diff);

                // If all the blocks are used, start using ladders
                if (B < 0) {
                    B += maxB.poll();
                    L--;
                }

                // If all the ladders and blocks are used, break
                if (L < 0)
                    break;
            }
            currentTower++;
        }

        System.out.println(currentTower);
    }
}
Python
# code by Flutterfly
import heapq

# Input
N, B, L = 9, 10, 2
heights = [4, 12, 2, 7, 3, 18, 20, 3, 19]

# Max heap to store the difference between two adjacent
# towers, which we have covered using blocks
maxB = []
currentTower = 0

while currentTower < N - 1:
    # Calculate the difference between the current
    # tower and the next tower
    diff = heights[currentTower + 1] - heights[currentTower]

    if diff > 0:
        B -= diff
        # Use blocks to cover the difference between
        # the current and the next tower
        heapq.heappush(maxB, -diff)

        # If all the blocks are used, start using ladders
        if B < 0:
            B += -heapq.heappop(maxB)
            L -= 1

        # If all the ladders and blocks are used, break
        if L < 0:
            break

    currentTower += 1

print(currentTower)
C#
using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // Input
        int N = 9, B = 10, L = 2;
        int[] heights = { 4, 12, 2, 7, 3, 18, 20, 3, 19 };

        // Max heap to store difference between two adjacent
        // towers which we have covered using blocks
        var maxB = new PriorityQueue<int>((a, b) => b.CompareTo(a));
        int currentTower = 0;

        while (currentTower < N - 1)
        {
            // Calculate the difference between the current
            // tower and the next tower
            int diff = heights[currentTower + 1] - heights[currentTower];

            if (diff > 0)
            {
                B -= diff;
                // Use blocks to cover the difference between
                // the current and the next tower
                maxB.Enqueue(diff);

                // If all the blocks are used, start using
                // ladders
                if (B < 0)
                {
                    B += maxB.Dequeue();
                    L--;
                }

                // If all the ladders and blocks are used, break
                if (L < 0)
                    break;
            }
            currentTower++;
        }

        Console.WriteLine(currentTower);
    }
}

// Priority Queue implementation for C#
public class PriorityQueue<T>
{
    private List<T> data;
    private readonly Comparison<T> comparison;

    public PriorityQueue(Comparison<T> comparison)
    {
        this.comparison = comparison;
        this.data = new List<T>();
    }

    public void Enqueue(T item)
    {
        data.Add(item);
        int childIndex = data.Count - 1;
        while (childIndex > 0)
        {
            int parentIndex = (childIndex - 1) / 2;
            if (comparison(data[childIndex], data[parentIndex]) >= 0)
                break;
            T tmp = data[childIndex];
            data[childIndex] = data[parentIndex];
            data[parentIndex] = tmp;
            childIndex = parentIndex;
        }
    }

    public T Dequeue()
    {
        int lastIndex = data.Count - 1;
        T frontItem = data[0];
        data[0] = data[lastIndex];
        data.RemoveAt(lastIndex--);

        int parentIndex = 0;
        while (true)
        {
            int leftChildIndex = parentIndex * 2 + 1;
            int rightChildIndex = parentIndex * 2 + 2;
            int minIndex = parentIndex;

            if (leftChildIndex <= lastIndex && comparison(data[leftChildIndex], data[minIndex]) < 0)
                minIndex = leftChildIndex;
            if (rightChildIndex <= lastIndex && comparison(data[rightChildIndex], data[minIndex]) < 0)
                minIndex = rightChildIndex;
            if (minIndex == parentIndex)
                break;

            T tmp = data[parentIndex];
            data[parentIndex] = data[minIndex];
            data[minIndex] = tmp;
            parentIndex = minIndex;
        }
        return frontItem;
    }

    public int Count => data.Count;

    public override string ToString()
    {
        return string.Join(", ", data);
    }
}

// This code is contributed by shivamgupta310570
Javascript
// Function to calculate the maximum number
// of towers that can be reached
function calculateMaxTowers() {
    // Input
    let N = 9, B = 10, L = 2;
    let heights = [4, 12, 2, 7, 3, 18, 20, 3, 19];

    // Max heap to store difference between two adjacent
    // towers which we have covered using blocks
    let maxB = [];
    let currentTower = 0;

    while (currentTower < N - 1) {
        // Calculate the difference between the current
        // tower and the next tower
        let diff = heights[currentTower + 1] - heights[currentTower];

        if (diff > 0) {
            B -= diff;
            // Use blocks to cover the difference between
            // the current and the next tower
            maxB.push(diff);

            // If all the blocks are used, start using
            // ladders
            if (B < 0) {
                B += Math.max(...maxB);
                maxB.splice(maxB.indexOf(Math.max(...maxB)), 1);
                L--;
            }

            // If all the ladders and blocks are used, break
            if (L < 0)
                break;
        }
        currentTower++;
    }

    console.log(currentTower);
}

// Call the function to calculate the maximum
// number of towers that can be reached
calculateMaxTowers();

Output
7






Time Complexity: O(N * logN), where N is the size of input array heights[].
Auxiliary Space: O(N)

Method 2: Using Binary Search
Approach:

  1. Perform a binary search to find the furthest building index that can be reached.
  2. Initialize the lo to 0 and hi to n-1
  3. Calculate the middle index mid and calls the check function to determine if the building at index mid can be reached.
  4. If check returns true, it means the furthest building can be reached with the current constraints, so the binary search is continued on the right half (lo = mid).
  5. If check returns false, it means the furthest building cannot be reached with the current constraints, so the binary search is continued on the left half (hi = mid – 1).
  6. After the binary search loop completes, it returns the value of lo. This represents the furthest building index that can be reached.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

    bool check(vector<int>& heights, int bricks, int ladders, int mid) {
        // Store the height differences that are greater than the previous one
        vector<int> diff;
        for (int i = 1; i <= mid; i++) {
            if (heights[i] > heights[i - 1]) {
                diff.push_back(heights[i] - heights[i - 1]);
            }
        }
        // Sort them in decreasing order
        sort(diff.begin(), diff.end(), greater<int>());
        int l = diff.size();
        for (int i = ladders; i < l; i++) {
            if (diff[i] > bricks) {
                return false;
            }
            bricks -= diff[i];
        }
        return true;
    }

    int furthestBuilding(vector<int>& heights, int bricks, int ladders) {
        int n = heights.size();
        int lo = 0, hi = n - 1;
        // Binary search loop
        while (lo < hi) {
            int mid = (lo + hi + 1) / 2;
          if (check(heights, bricks, ladders, mid)) {
                lo = mid;  // If true, then binary search on the right half
            } else {
                hi = mid - 1; // If false, then binary search on the left half
            }
        }
        return lo;
    }

int main() {
    vector<int> heights = { 4, 12, 2, 7, 3, 18, 20, 3, 19 };
    int bricks = 10;
    int ladders = 2;

    int result = furthestBuilding(heights, bricks, ladders);
    cout << result << endl;

    return 0;
}
Java
// Java Code

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class GFG {

    // Method to check if it's possible to reach the furthest building
    static boolean check(List<Integer> heights, int bricks, int ladders, int mid) {
        // Store the height differences that are greater than the previous one
        List<Integer> diff = new ArrayList<>();
        for (int i = 1; i <= mid; i++) {
            if (heights.get(i) > heights.get(i - 1)) {
                diff.add(heights.get(i) - heights.get(i - 1));
            }
        }
        // Sort them in decreasing order
        Collections.sort(diff, Collections.reverseOrder());
        int l = diff.size();
        for (int i = ladders; i < l; i++) {
            if (diff.get(i) > bricks) {
                return false;
            }
            bricks -= diff.get(i);
        }
        return true;
    }

    // Method to find the furthest building that can be reached
    static int furthestBuilding(List<Integer> heights, int bricks, int ladders) {
        int n = heights.size();
        int lo = 0, hi = n - 1;
        // Binary search loop
        while (lo < hi) {
            int mid = (lo + hi + 1) / 2;
            if (check(heights, bricks, ladders, mid)) {
                lo = mid;  // If true, then binary search on the right half
            } else {
                hi = mid - 1; // If false, then binary search on the left half
            }
        }
        return lo;
    }

    public static void main(String[] args) {
        List<Integer> heights = new ArrayList<>();
        heights.add(4);
        heights.add(12);
        heights.add(2);
        heights.add(7);
        heights.add(3);
        heights.add(18);
        heights.add(20);
        heights.add(3);
        heights.add(19);
        int bricks = 10;
        int ladders = 2;

        int result = furthestBuilding(heights, bricks, ladders);
        System.out.println(result);
    }
}

// This code is contributed by guptapratik
JavaScript
// JavaScript Code

// Method to check if it's possible to reach the furthest building
function check(heights, bricks, ladders, mid) {
    // Store the height differences that are greater than the previous one
    let diff = [];
    for (let i = 1; i <= mid; i++) {
        if (heights[i] > heights[i - 1]) {
            diff.push(heights[i] - heights[i - 1]);
        }
    }
    // Sort them in decreasing order
    diff.sort((a, b) => b - a);
    let l = diff.length;
    for (let i = ladders; i < l; i++) {
        if (diff[i] > bricks) {
            return false;
        }
        bricks -= diff[i];
    }
    return true;
}

// Method to find the furthest building that can be reached
function furthestBuilding(heights, bricks, ladders) {
    let n = heights.length;
    let lo = 0, hi = n - 1;
    // Binary search loop
    while (lo < hi) {
        let mid = Math.floor((lo + hi + 1) / 2);
        if (check(heights, bricks, ladders, mid)) {
            lo = mid;  // If true, then binary search on the right half
        } else {
            hi = mid - 1; // If false, then binary search on the left half
        }
    }
    return lo;
}

function main() {
    let heights = [4, 12, 2, 7, 3, 18, 20, 3, 19];
    let bricks = 10;
    let ladders = 2;

    let result = furthestBuilding(heights, bricks, ladders);
    console.log(result);
}

main();


// This code is contributed by guptapratik
Python3
# Python Code

def check(heights, bricks, ladders, mid):
    # Store the height differences that are greater than the previous one
    diff = []
    for i in range(1, mid + 1):
        if heights[i] > heights[i - 1]:
            diff.append(heights[i] - heights[i - 1])
    # Sort them in decreasing order
    diff.sort(reverse=True)
    l = len(diff)
    for i in range(ladders, l):
        if diff[i] > bricks:
            return False
        bricks -= diff[i]
    return True

def furthestBuilding(heights, bricks, ladders):
    n = len(heights)
    lo, hi = 0, n - 1
    # Binary search loop
    while lo < hi:
        mid = (lo + hi + 1) // 2
        if check(heights, bricks, ladders, mid):
            lo = mid  # If true, then binary search on the right half
        else:
            hi = mid - 1  # If false, then binary search on the left half
    return lo

def main():
    heights = [4, 12, 2, 7, 3, 18, 20, 3, 19]
    bricks = 10
    ladders = 2

    result = furthestBuilding(heights, bricks, ladders)
    print(result)

if __name__ == "__main__":
    main()
    
# This code is contributed by guptapratik

Output
7

Time Complexity: O(log(n) * mid * log(mid))




Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads