Worker-Bike Assignments (Campus Bikes)
Last Updated :
18 Apr, 2024
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));
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).
Share your thoughts in the comments
Please Login to comment...