Open In App

Program for Bridge and Torch problem

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of positive distinct integer denoting the crossing time of ‘n’ people. These ‘n’ people are standing at one side of bridge. Bridge can hold at max two people at a time. When two people cross the bridge, they must move at the slower person’s pace. Find the minimum total time in which all persons can cross the bridge. See this puzzle to understand more

Note: Slower person space is given by larger time. 

Input:  Crossing Times = {10, 20, 30}
Output: 60
Explanation
1. Firstly person '1' and '2' cross the bridge
   with total time about 20 min(maximum of 10, 20) 
2. Now the person '1' will come back with total 
   time of '10' minutes.
3. Lastly the person '1' and '3' cross the bridge
   with total time about 30 minutes
Hence total time incurred in whole journey will be
20 + 10 + 30 = 60

Input: Crossing Times = [1, 2, 5, 8}
Output: 15
Explanation
See this for full explanation.

The approach is to use Dynamic programming. Before getting dive into dynamic programming let’s see the following observation that will be required in solving the problem. 

  1. When any two people cross the bridge, then the fastest person crossing time will not be contributed in answer as both of them move with slowest person speed. 
  2. When some of the people will cross the river and reached the right side then only the fastest people(smallest integer) will come back to the left side. 
  3. Person can only be present either left side or right side of the bridge. Thus, if we maintain the left mask, then right mask can easily be calculated by setting the bits ‘1’ which is not present in the left mask. For instance, Right_mask = ((2n) – 1) XOR (left_mask). 
  4. Any person can easily be represented by bitmask(usually called as ‘mask’). When ith bit of ‘mask’ is set, that means that person is present at left side of the bridge otherwise it would be present at right side of bridge. For instance, let the mask of 6 people is 100101, which represents the person 1, 4, 6 are present at left side of bridge and the person 2, 3 and 5 are present at the right side of the bridge.

Implementation:

C++

// C++ program to find minimum time required to
// send people on other side of bridge
#include <bits/stdc++.h>
using namespace std;
 
/* Global dp[2^20][2] array, in dp[i][j]--
   'i' denotes mask in which 'set bits' denotes
   total people standing at left side of bridge
   and 'j' denotes the turn that represent on
   which side we have to send people either
   from left to right(0) or from right to
   left(1)  */
int dp[1 << 20][2];
 
/* Utility function to find total time required
   to send people to other side of bridge */
int findMinTime(int leftmask, bool turn, int arr[], int& n)
{
 
    // If all people has been transferred
    if (!leftmask)
        return 0;
 
    int& res = dp[leftmask][turn];
 
    // If we already have solved this subproblem,
    // return the answer.
    if (~res)
        return res;
 
    // Calculate mask of right side of people
    int rightmask = ((1 << n) - 1) ^ leftmask;
 
    /* if turn == 1 means currently people are at
     right side, thus we need to transfer
     people to the left side */
    if (turn == 1) {
        int minRow = INT_MAX, person;
        for (int i = 0; i < n; ++i) {
 
            // Select one people whose time is less
            // among all others present at right
            // side
            if (rightmask & (1 << i)) {
                if (minRow > arr[i]) {
                    person = i;
                    minRow = arr[i];
                }
            }
        }
 
        // Add that person to answer and recurse for next
        // turn after initializing that person at left side
        res = arr[person]
              + findMinTime(leftmask | (1 << person),
                            turn ^ 1, arr, n);
    }
    else {
 
        // __builtin_popcount() is inbuilt gcc function
        // which will count total set bits in 'leftmask'
        if (__builtin_popcount(leftmask) == 1) {
            for (int i = 0; i < n; ++i) {
 
                // Since one person is present at left
                // side, thus return that person only
                if (leftmask & (1 << i)) {
                    res = arr[i];
                    break;
                }
            }
        }
        else {
 
            // try for every pair of people by
            // sending them to right side
 
            // Initialize the result with maximum value
            res = INT_MAX;
            for (int i = 0; i < n; ++i) {
 
                // If ith person is not present then
                // skip the rest loop
                if (!(leftmask & (1 << i)))
                    continue;
 
                for (int j = i + 1; j < n; ++j) {
                    if (leftmask & (1 << j)) {
 
                        // Find maximum integer(slowest
                        // person's time)
                        int val = max(arr[i], arr[j]);
 
                        // Recurse for other people after
                        // un-setting the ith and jth bit of
                        // left-mask
                        val += findMinTime(
                            leftmask ^ (1 << i) ^ (1 << j),
                            turn ^ 1, arr, n);
                        // Find minimum answer among
                        // all chosen values
                        res = min(res, val);
                    }
                }
            }
        }
    }
    return res;
}
 
// Utility function to find minimum time
int findTime(int arr[], int n)
{
    // Find the mask of 'n' peoples
    int mask = (1 << n) - 1;
 
    // Initialize all entries in dp as -1
    memset(dp, -1, sizeof(dp));
 
    return findMinTime(mask, 0, arr, n);
}
 
// Driver program
int main()
{
    int arr[] = { 10, 20, 30 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << findTime(arr, n);
    return 0;
}

                    

Java

// Java program to find minimum time required to
// send people on other side of bridge
import java.io.*;
 
class GFG {
    /* Global dp[2^20][2] array, in dp[i][j]--
         'i' denotes mask in which 'set bits' denotes
         total people standing at left side of bridge
         and 'j' denotes the turn that represent on
         which side we have to send people either
         from left to right(0) or from right to
         left(1)  */
    static int dp[][] = new int[1 << 20][2];
 
    /* Utility function to find total time required
       to send people to other side of bridge */
    public static int findMinTime(int leftmask,
                                  boolean turn, int arr[],
                                  int n)
    {
 
        // If all people has been transferred
        if (leftmask == 0)
            return 0;
 
        int res = dp[leftmask][turn == true ? 1 : 0];
 
        // If we already have solved this subproblem,
        // return the answer.
        if (~res != 0)
            return res;
 
        // Calculate mask of right side of people
        int rightmask = ((1 << n) - 1) ^ leftmask;
 
        /* if turn == 1 means currently people are at
         right side, thus we need to transfer
         people to the left side */
        if (turn == true) {
            int minRow = Integer.MAX_VALUE, person = 0;
            for (int i = 0; i < n; ++i) {
 
                // Select one people whose time is less
                // among all others present at right
                // side
                if ((rightmask & (1 << i)) != 0) {
                    if (minRow > arr[i]) {
                        person = i;
                        minRow = arr[i];
                    }
                }
            }
 
            // Add that person to answer and recurse for
            // next turn after initializing that person at
            // left side
            res = arr[person]
                  + findMinTime(leftmask | (1 << person),
                                !turn, arr, n);
        }
        else {
 
            // __builtin_popcount() is inbuilt gcc function
            // which will count total set bits in 'leftmask'
            if (Integer.bitCount(leftmask) == 1) {
                for (int i = 0; i < n; ++i) {
 
                    // Since one person is present at left
                    // side, thus return that person only
                    if ((leftmask & (1 << i)) != 0) {
                        res = arr[i];
                        break;
                    }
                }
            }
            else {
 
                // try for every pair of people by
                // sending them to right side
 
                // Initialize the result with maximum value
                res = Integer.MAX_VALUE;
                for (int i = 0; i < n; ++i) {
 
                    // If ith person is not present then
                    // skip the rest loop
                    if ((leftmask & (1 << i)) == 0)
                        continue;
 
                    for (int j = i + 1; j < n; ++j) {
                        if ((leftmask & (1 << j)) != 0) {
 
                            // Find maximum integer(slowest
                            // person's time)
                            int val
                                = Math.max(arr[i], arr[j]);
 
                            // Recurse for other people
                            // after un-setting the ith and
                            // jth bit of left-mask
                            val += findMinTime(
                                (leftmask ^ (1 << i)
                                 ^ (1 << j)),
                                !turn, arr, n);
                            // Find minimum answer among
                            // all chosen values
                            res = Math.min(res, val);
                        }
                    }
                }
            }
        }
        return res;
    }
 
    // Utility function to find minimum time
    public static int findTime(int arr[], int n)
    {
        // Find the mask of 'n' peoples
        int mask = (1 << n) - 1;
 
        // Initialize all entries in dp as -1
        for (int i = 0; i < (1 << 20); i++) {
            dp[i][0] = -1;
            dp[i][1] = -1;
        }
 
        return findMinTime(mask, false, arr, n);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int arr[] = { 10, 20, 30 };
        int n = 3;
        System.out.print(findTime(arr, n));
    }
}
 
// This code is contributed by Rohit Pradhan

                    

Python3

# Python program to find minimum time required
# to send people on other side of bridge
dp = [[0 for x in range(2)] for y in range(1 << 20)]
 
# Counts set bits in a number
def countSetBits(n):
   
    # Using bin function in number
    ans = bin(n)
    return ans.count("1")
 
 
# Utility function to find total time required
# to send people to other side of bridge
def findMinTime(leftmask, turn, arr, n):
        # If all people has been transferred
    if(leftmask == 0):
        return 0
 
    res = dp[leftmask][1 if(turn == True) else 0]
 
    # If we already have solved this subproblem,
    # return the answer.
    if(~res != 0):
        return res
 
    # Calculate mask of right side of people
    rightmask = ((1 << n)-1) ^ leftmask
 
    # if turn == 1 means currently people are at
    # right side, thus we need to transfer
    # people to the left side
    if(turn == True):
        minRow = float('inf')
        person = 0
        for i in range(n):
                # Select one people whose time is less
            # among all others present at right
            # side
            if((rightmask & (1 << i)) != 0):
                if(minRow > arr[i]):
                    person = i
                    minRow = arr[i]
 
        # Add that person to answer and recurse for
        # next turn after initializing that person at
        # left side
        res = arr[person] + \
            findMinTime(leftmask | (1 << person), not turn, arr, n)
    else:
        # count total set bits in 'leftmask'
        if(countSetBits(leftmask) == 1):
            for i in range(n):
                # Since one person is present at left
                # side, thus return that person only
                if((leftmask & (1 << i)) != 0):
                    res = arr[i]
                    break
        else:
                # try for every pair of people by
            # sending them to right side
 
                # Initialize the result with maximum value
            res = float('inf')
            for i in range(n):
                # If ith person is not present then skip the rest loop
                if((leftmask & (1 << i)) == 0):
                    continue
                for j in range(i+1, n):
                    if((leftmask & (1 << j)) != 0):
                        # Find maximum integer(slowest person's time)
                        val = max(arr[i], arr[j])
                        # Recurse for other people after un-setting the ith and jth bit of left-mask
                        val += findMinTime((leftmask ^ (1 << i)
                                            ^ (1 << j)), not turn, arr, n)
                        # Find minimum answer among all chosen values
                        res = min(res, val)
 
    return res
 
# Utility function to find minimum time
 
 
def findTime(arr, n):
        # Find the mask of 'n' peoples
    mask = (1 << n) - 1
 
    # Initialize all entries in dp as -1
    for i in range((1 << 20)):
        dp[i][0] = -1
        dp[i][1] = -1
 
    return findMinTime(mask, False, arr, n)
 
 
arr = [10, 20, 30]
n = 3
print(findTime(arr, n))
 
# This code is contributed by lokeshmvs21.

                    

C#

// Include namespace system
using System;
 
// This class are provide by kalkicode.com
public class Settlement {
    public static int IntegerBitCount(int i)
    {
        i = i - ((i >> 1) & 1431655765);
        i = (i & 858993459) + ((i >> 2) & 858993459);
        i = (i + (i >> 4)) & 252645135;
        i = i + (i >> 8);
        i = i + (i >> 16);
        return i & 63;
    }
}
 
public class GFG {
    // Global dp[2^20][2] array, in dp[i][j]--
    //         'i' denotes mask in which 'set bits' denotes
    //         total people standing at left side of bridge
    //         and 'j' denotes the turn that represent on
    //         which side we have to send people either
    //         from left to right(0) or from right to
    //         left(1)
    public static int[, ] dp = new int[1 << 20, 2];
    // Utility function to find total time required
    //       to send people to other side of bridge
    public static int findMinTime(int leftmask, bool turn,
                                  int[] arr, int n)
    {
        // If all people has been transferred
        if (leftmask == 0) {
            return 0;
        }
        var res = GFG.dp[leftmask, turn == true ? 1 : 0];
        // If we already have solved this subproblem,
        // return the answer.
        if (~res != 0) {
            return res;
        }
        // Calculate mask of right side of people
        var rightmask = ((1 << n) - 1) ^ leftmask;
        // if turn == 1 means currently people are at
        //         right side, thus we need to transfer
        //         people to the left side
        if (turn == true) {
            var minRow = int.MaxValue;
            var person = 0;
            for (int i = 0; i < n; ++i) {
                // Select one people whose time is less
                // among all others present at right
                // side
                if ((rightmask & (1 << i)) != 0) {
                    if (minRow > arr[i]) {
                        person = i;
                        minRow = arr[i];
                    }
                }
            }
            // Add that person to answer and recurse for
            // next turn after initializing that person at
            // left side
            res = arr[person]
                  + GFG.findMinTime(leftmask
                                        | (1 << person),
                                    !turn, arr, n);
        }
        else {
            // __builtin_popcount() is inbuilt gcc function
            // which will count total set bits in 'leftmask'
            if (Settlement.IntegerBitCount(leftmask) == 1) {
                for (int i = 0; i < n; ++i) {
                    // Since one person is present at left
                    // side, thus return that person only
                    if ((leftmask & (1 << i)) != 0) {
                        res = arr[i];
                        break;
                    }
                }
            }
            else {
                // try for every pair of people by
                // sending them to right side
                // Initialize the result with maximum value
                res = int.MaxValue;
                for (int i = 0; i < n; ++i) {
                    // If ith person is not present then
                    // skip the rest loop
                    if ((leftmask & (1 << i)) == 0) {
                        continue;
                    }
                    for (int j = i + 1; j < n; ++j) {
                        if ((leftmask & (1 << j)) != 0) {
                            // Find maximum integer(slowest
                            // person's time)
                            var val
                                = Math.Max(arr[i], arr[j]);
                            // Recurse for other people
                            // after un-setting the ith and
                            // jth bit of left-mask
                            val += GFG.findMinTime(
                                (leftmask ^ (1 << i)
                                 ^ (1 << j)),
                                !turn, arr, n);
                            // Find minimum answer among
                            // all chosen values
                            res = Math.Min(res, val);
                        }
                    }
                }
            }
        }
        return res;
    }
    // Utility function to find minimum time
    public static int findTime(int[] arr, int n)
    {
        // Find the mask of 'n' peoples
        var mask = (1 << n) - 1;
        // Initialize all entries in dp as -1
        for (int i = 0; i < (1 << 20); i++) {
            GFG.dp[i, 0] = -1;
            GFG.dp[i, 1] = -1;
        }
        return GFG.findMinTime(mask, false, arr, n);
    }
    // Driver Code
    public static void Main(String[] args)
    {
        int[] arr = { 10, 20, 30 };
        var n = 3;
        Console.Write(GFG.findTime(arr, n));
    }
}

                    

Javascript

// Javascript program to find minimum time required to
    // send people on other side of bridge
 
    //Function to count set bits
    function countSetBits(n) {
      var count = 0;
      while (n) {
        count += n & 1;
        n >>= 1;
      }
      return count;
    }
    /* Global dp array of (2^20)*(2) elements, in dp[i][j]--
       'i' denotes mask in which 'set bits' denotes
       total people standing at left side of bridge
       and 'j' denotes the turn that represent on
       which side we have to send people either
       from left to right(0) or from right to
       left(1)  */
 
    var dp = Array.from(Array(1 << 20), () => new Array(2));
    /* Utility function to find total time required
       to send people to other side of bridge */
    function findMinTime(leftmask, turn, arr, n) {
      // If all people has been transferred
      if (!leftmask) return 0;
 
      var res = dp[leftmask][turn];
 
      // If we already have solved this subproblem,
      // return the answer.
      if (~res) return res;
 
      // Calculate mask of right side of people
      var rightmask = ((1 << n) - 1) ^ leftmask;
 
      /* if turn == 1 means currently people are at
         right side, thus we need to transfer
         people to the left side */
      if (turn == 1) {
        var minRow = Number.MAX_VALUE,
          person = 0;
        for (var i = 0; i < n; ++i) {
          // Select one people whose time is less
          // among all others present at right
          // side
          if (rightmask & (1 << i)) {
            if (minRow > arr[i]) {
              person = i;
              minRow = arr[i];
            }
          }
        }
 
        // Add that person to answer and recurse for next
        // turn after initializing that person at left side
        res =
          arr[person] +
          findMinTime(leftmask | (1 << person), turn ^ 1, arr, n);
      } else {
        // countSetBits() is a function
        // which will count total set bits in 'leftmask'
        if (countSetBits(leftmask) == 1) {
          for (var i = 0; i < n; ++i) {
            // Since one person is present at left
            // side, thus return that person only
            if (leftmask & (1 << i)) {
              res = arr[i];
              break;
            }
          }
        } else {
          // try for every pair of people by
          // sending them to right side
 
          // Initialize the result with maximum value
          res = Number.MAX_VALUE;
          for (var i = 0; i < n; ++i) {
            // If ith person is not present then
            // skip the rest loop
            if (!(leftmask & (1 << i))) continue;
 
            for (var j = i + 1; j < n; ++j) {
              if (leftmask & (1 << j)) {
                // Find maximum integer(slowest
                // person's time)
                var val = Math.max(arr[i], arr[j]);
 
                // Recurse for other people after
                // un-setting the ith and jth bit of
                // left-mask
                val += findMinTime(
                  leftmask ^ (1 << i) ^ (1 << j),
                  turn ^ 1,
                  arr,
                  n
                );
                // Find minimum answer among
                // all chosen values
                res = Math.min(res, val);
              }
            }
          }
        }
      }
      return res;
    }
 
    // Utility function to find minimum time
    function findTime(arr, n) {
      // Find the mask of 'n' peoples
      var mask = (1 << n) - 1;
 
      // Initialize all entries in dp as -1
      for (var k = 0; k < 1 << 20; k++) {
        dp[k][0] = -1;
        dp[k][1] = -1;
      }
 
      return findMinTime(mask, 0, arr, n);
    }
 
    // Driver program
 
    var arr = [10, 20, 30];
    var n = arr.length;
    console.log(findTime(arr, n));

                    

Output
60

Time complexity:  O(N2)
Auxiliary space:        O(220) = O(1)



Last Updated : 13 Jan, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads