1066 - Campus Bikes II (Medium)
Problem Link
https://leetcode.com/problems/campus-bikes-ii/
Problem Statement
On a campus represented as a 2D grid, there are n
workers and m
bikes, with n <= m
. Each worker and bike is a 2D coordinate on this grid.
We assign one unique bike to each worker so that the sum of the Manhattan distances between each worker and their assigned bike is minimized.
Return the minimum possible sum of Manhattan distances between each worker and their assigned bike
.
The Manhattan distance between two points p1
and p2
is Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|
.
Example 1:
Input: workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]]
Output: 6
Explanation:
We assign bike 0 to worker 0, bike 1 to worker 1. The Manhattan distance of both assignments is 3, so the output is 6.
Example 2:
Input: workers = [[0,0],[1,1],[2,0]], bikes = [[1,0],[2,2],[2,1]]
Output: 4
Explanation:
We first assign bike 0 to worker 0, then assign bike 1 to worker 1 or worker 2, bike 2 to worker 2 or worker 1. Both assignments lead to sum of the Manhattan distances as 4.
Example 3:
Input: workers = [[0,0],[1,0],[2,0],[3,0],[4,0]], bikes = [[0,999],[1,999],[2,999],[3,999],[4,999]]
Output: 4995
Constraints:
n == workers.length
m == bikes.length
1 <= n <= m <= 10
workers[i].length == 2
bikes[i].length == 2
0 <= workers[i][0], workers[i][1], bikes[i][0], bikes[i][1] < 1000
- All the workers and the bikes locations are unique.
Approach 1: DP Bit Masking
Iterate each mask from to where is the size of . For each mask, we try to find each bike that is not in use and calculate the Manhattan distance and try the next . We memorise the result to speed up the whole process.
class Solution {
public:
vector<int> dp;
int n, m;
int dfs(vector<vector<int>>& workers, vector<vector<int>>& bikes, int workerIdx, int mask) {
// worker idx out of range
if (workerIdx >= n) return 0;
// calculated before, return immediately
if (dp[mask] != -1) return dp[mask];
// init res
int res = INT_MAX;
// iterate each mask
for (int bikeIdx = 0; bikeIdx < m; bikeIdx++) {
// this bike is not in use
if (!(mask & (1 << bikeIdx))) {
// calculate the Manhattan distance
int dist = abs(workers[workerIdx][0] - bikes[bikeIdx][0]) + abs(workers[workerIdx][1] - bikes[bikeIdx][1]);
res = min(res, dist + dfs(workers, bikes, workerIdx + 1, mask | (1 << bikeIdx)));
}
}
// memoize the smallest distance sum for this mask
return dp[mask] = res;
}
int assignBikes(vector<vector<int>>& workers, vector<vector<int>>& bikes) {
n = workers.size(), m = bikes.size();
dp = vector<int>(1 << m, -1);
return dfs(workers, bikes, 0, 0);
}
};
We can also write like this.
class Solution {
public:
int assignBikes(vector<vector<int>>& workers, vector<vector<int>>& bikes) {
int n = workers.size(), m = bikes.size(), ans = 1e9;
vector<int> dp(1 << m, 1e9);
dp[0] = 0;
// iterate each mask
for (int mask = 0; mask < (1 << m); mask++) {
// worker idx
int workerIdx = __builtin_popcount(mask);
// all workers got the bikes
// update the answer
if (workerIdx >= n) {
ans = min(ans, dp[mask]);
continue;
}
// iterate each bike
for (int bikeIdx = 0; bikeIdx < m; bikeIdx++) {
// this bike is not in use
if (!(mask & (1 << bikeIdx))) {
// calculate the Manhattan distance
int dist = abs(workers[workerIdx][0] - bikes[bikeIdx][0]) + abs(workers[workerIdx][1] - bikes[bikeIdx][1]);
// new mask = current mask + this bike
int newMask = mask | (1 << bikeIdx);
// update distance sum
dp[newMask] = min(dp[newMask], dist + dp[mask]);
}
}
}
return ans;
}
};