Open In App

Worker-Bike Assignments (Campus Bikes)

Last Updated : 18 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array workers[] and bikes[], which represents position of workers and bikes on a 2D plane, the task is to assign each worker to a bike based on the shortest Manhattan distance between them. If multiple pairs share the same distance then prioritize by worker’s index and then by bike index. Provide a list showing which bike is assigned to a worker.

Note: The Manhattan distance between two points p1 and p2 is Manhattan(p1, p2) = |p1.x – p2.x| + |p1.y – p2.y|.

Constraints: 1 <= workers.length <= bike.length <= 10

Example:

Input: workers = {{0,0},{2,1}}, bikes = {{1,2},{3,3}}
Output: {1,0}
Explanation: Worker 1 selects Bike 0 as it is the closest without ties, and Worker 0 is assigned Bike 1.

Input: workers = {{0,0},{1,1},{2,0}}, bikes = {{1,0},{2,2},{2,1}}
Output: {0,2,1}
Explanation: Worker 0 chooses Bike 0 initially. Worker 1 and Worker 2 have the same distance to Bike 2, so Worker 1 is assigned to Bike 2, and Worker 2 takes Bike 1.

Approach:

This approach use dp with bitmasking technique to keep track of which bikes have been assigned to workers. Bitmasking is a way to use bits to represent a set of items. In this case, each bit in an integer represents a package.

Now, for each driver, starting from the first one, we go through the bikes and assign an available package to the driver. We can check if a package is available by looking at the corresponding bit in our integer. If the bit is 0, the package is available.

When we assign a package to a driver, we need to mark it as unavailable for the other workers. We do this by changing the corresponding bit in our integer from 0 to 1.

In this approach, we use bitwise operations to check, set, and unset bits in our integer. Here’s how:

  • Bitwise AND(&) : We can use this operation to check if a bit is set(1). If the result of bitmask & (1 << i) is not 0, then the ith bit is set.
  • Bitwise OR(|) : We can use this operation to set a bit(make it 1).The expression bitmask | (1 << i) will set the ith bit.
  • Bitwise XOR(^) : We can use this operation to unset a bit(make it 0).The expression bitmask ^ (1 << i) will unset the ith bit if it is set.

Steps-by-step approach:

  • Create an array memo[] of size 1024 to store the results of subproblems to avoid redundant calculations.
  • If all drivers have been assigned a package, returns 0.
  • If the result for the current mask has been calculated, it returns the stored result.
  • For each available package, calculates the total distance and keeps track of the smallest total distance.
  • Update the mask to indicate that the current package has been assigned and recursively calls itself for the next driver.
  • The smallest total distance is stored in the memo[] array and returned.

Below are the implementation of the above approach:

C++
#include <bits/stdc++.h>
using namespace std;

// Maximum value of mask will be 2^(Number of bikes)
// and number of bikes can be 10 at max
int memo[1024];

// Manhattan distance
int findDistance(vector<int>& worker, vector<int>& package)
{
    return abs(worker[0] - package[0])
           + abs(worker[1] - package[1]);
}

int minimumDistanceSum(vector<vector<int> >& workers,
                       vector<vector<int> >& bikes,
                       int driverIdx, int mask)
{
    if (driverIdx >= workers.size()) {
        return 0;
    }

    // If result is already calculated, return it no
    // recursion needed
    if (memo[mask] != -1)
        return memo[mask];

    int smallestDistanceSum = INT_MAX;
    for (int packageIdx = 0; packageIdx < bikes.size();
         packageIdx++) {
        // Check if the package at packageIdx is available
        if ((mask & (1 << packageIdx)) == 0) {
            // Adding the current distance and repeat the
            // process for next worker also changing the bit
            // at index packageIdx to 1 to show the package
            // there is assigned
            smallestDistanceSum
                = min(smallestDistanceSum,
                      findDistance(workers[driverIdx],
                                   bikes[packageIdx])
                          + minimumDistanceSum(
                              workers, bikes, driverIdx + 1,
                              mask | (1 << packageIdx)));
        }
    }

    // Memoizing the result corresponding to mask
    return memo[mask] = smallestDistanceSum;
}

int assignpackages(vector<vector<int> >& workers,
                   vector<vector<int> >& bikes)
{
    // Marking all positions to -1 that signifies result
    // has not been calculated yet for this mask
    memset(memo, -1, sizeof(memo));
    return minimumDistanceSum(workers, bikes, 0, 0);
}

int main()
{

    vector<vector<int> > workers = { { 0, 0 }, { 2, 1 } };
    vector<vector<int> > bikes = { { 1, 2 }, { 3, 3 } };
    cout << assignpackages(workers, bikes) << endl;
    return 0;
}
Java
/*package whatever //do not write package name here */

import java.util.Arrays;

public class GFG {

    static int[] memo = new int[1024];

    // Manhattan distance
    static int findDistance(int[] worker, int[] packageCoord) {
        return Math.abs(worker[0] - packageCoord[0])
                + Math.abs(worker[1] - packageCoord[1]);
    }

    static int minimumDistanceSum(int[][] workers, int[][] bikes, int driverIdx, int mask) {
        if (driverIdx >= workers.length) {
            return 0;
        }

        // If result is already calculated, return it no
        // recursion needed
        if (memo[mask] != -1)
            return memo[mask];

        int smallestDistanceSum = Integer.MAX_VALUE;
        for (int packageIdx = 0; packageIdx < bikes.length; packageIdx++) {
            // Check if the package at packageIdx is available
            if ((mask & (1 << packageIdx)) == 0) {
                // Adding the current distance and repeat the
                // process for next worker also changing the bit
                // at index packageIdx to 1 to show the package
                // there is assigned
                smallestDistanceSum = Math.min(smallestDistanceSum,
                        findDistance(workers[driverIdx], bikes[packageIdx])
                                + minimumDistanceSum(workers, bikes, driverIdx + 1, mask | (1 << packageIdx)));
            }
        }

        // Memoizing the result corresponding to mask
        return memo[mask] = smallestDistanceSum;
    }

    static int assignPackages(int[][] workers, int[][] bikes) {
        // Marking all positions to -1 that signifies result
        // has not been calculated yet for this mask
        Arrays.fill(memo, -1);
        return minimumDistanceSum(workers, bikes, 0, 0);
    }

    public static void main(String[] args) {

        int[][] workers = {{0, 0}, {2, 1}};
        int[][] bikes = {{1, 2}, {3, 3}};

        System.out.println(assignPackages(workers, bikes));
    }
}
Python3
# Manhattan distance
def findDistance(worker, package):
    return abs(worker[0] - package[0]) + abs(worker[1] - package[1])

def minimumDistanceSum(workers, bikes, driverIdx, mask):
    if driverIdx >= len(workers):
        return 0

    # If result is already calculated, return it no recursion needed
    if memo[mask] != -1:
        return memo[mask]

    smallestDistanceSum = float('inf')
    for packageIdx in range(len(bikes)):
        # Check if the package at packageIdx is available
        if not mask & (1 << packageIdx):
            # Adding the current distance and repeat the process for next worker
            # also changing the bit at index packageIdx to 1 to show the package
            # there is assigned
            smallestDistanceSum = min(smallestDistanceSum,
                                       findDistance(workers[driverIdx], bikes[packageIdx]) +
                                       minimumDistanceSum(workers, bikes, driverIdx + 1, mask | (1 << packageIdx)))

    # Memoizing the result corresponding to mask
    memo[mask] = smallestDistanceSum
    return smallestDistanceSum

def assignPackages(workers, bikes):
    # Marking all positions to -1 that signifies result has not been calculated yet for this mask
    global memo
    memo = [-1] * (1 << len(bikes))
    return minimumDistanceSum(workers, bikes, 0, 0)

if __name__ == "__main__":
    workers = [[0, 0], [2, 1]]
    bikes = [[1, 2], [3, 3]]
    print(assignPackages(workers, bikes))
JavaScript
// Manhattan distance function
function findDistance(worker, package) {
    return Math.abs(worker[0] - package[0]) + Math.abs(worker[1] - package[1]);
}

// Function to calculate the minimum distance sum
function minimumDistanceSum(workers, bikes, driverIdx, mask, memo) {
    if (driverIdx >= workers.length) {
        return 0;
    }

    // If result is already calculated, return it, no recursion needed
    if (typeof memo[mask] !== 'undefined') {
        return memo[mask];
    }

    let smallestDistanceSum = Infinity;
    for (let packageIdx = 0; packageIdx < bikes.length; packageIdx++) {
        // Check if the package at packageIdx is available
        if (!(mask & (1 << packageIdx))) {
            // Adding the current distance and repeat the process for next worker
            // also changing the bit at index packageIdx to 1 to show the package
            // there is assigned
            smallestDistanceSum = Math.min(
                smallestDistanceSum,
                findDistance(workers[driverIdx], bikes[packageIdx]) +
                minimumDistanceSum(workers, bikes, driverIdx + 1, mask | (1 << packageIdx), memo)
            );
        }
    }

    // Memoizing the result corresponding to mask
    memo[mask] = smallestDistanceSum;
    return smallestDistanceSum;
}

// Function to assign packages to workers
function assignPackages(workers, bikes) {
    // Memoization array to store already calculated results
    const memo = new Array(1 << bikes.length).fill(undefined);
    return minimumDistanceSum(workers, bikes, 0, 0, memo);
}

// Driver code
const workers = [[0, 0], [2, 1]];
const bikes = [[1, 2], [3, 3]];
console.log(assignPackages(workers, bikes));

Output
6

Time Complexity: O(2^n * n^2), where n is the maximum number of packages (10 in this case).
Auxiliary space: O(2^n), where n is the maximum number of packages (10 in this case).



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads