Time to Cross a Bridge (2532)

This problem, which featured as the Hard in LeetCode Weekly 327, describes a situation in which some number of workers need to transfer boxes from one warehouse across a bridge to another. We are required to implement a function that returns the time it takes to transfer all boxes from the old warehouse across the bridge to the new warehouse.

This is a classic simulation exercise. The crux of the problem is this:

  1. Read the rules
  2. Read the rules again, carefully
  3. Efficiently simulate the situation

Turns out a priority queue is pretty great way to simulate a strictly-prioritized queue!


_86
class Solution {
_86
public:
_86
static int findCrossingTime(int n, int k, vector<vector<int>> &time) {
_86
const auto left_to_right = [&time] (int worker) { return time[worker][0]; };
_86
const auto pick_up_box = [&time] (int worker) { return time[worker][1]; };
_86
const auto right_to_left = [&time] (int worker) { return time[worker][2]; };
_86
const auto put_down_box = [&time] (int worker) { return time[worker][3]; };
_86
_86
vector<int> efficiency(k);
_86
vector<int> time_free(k, INT_MAX);
_86
_86
for (int i = 0; i < k; ++i) {
_86
efficiency[i] = left_to_right(i) + right_to_left(i);
_86
}
_86
_86
auto least_efficient = [&efficiency](int a, int b) {
_86
if (efficiency[a]==efficiency[b]) { return a < b; }
_86
return efficiency[a] < efficiency[b];
_86
};
_86
_86
auto first_free = [&time_free](int a, int b) {
_86
return time_free[a] > time_free[b];
_86
};
_86
_86
priority_queue<int, vector<int>, decltype(least_efficient)> left(least_efficient), right(least_efficient);
_86
priority_queue<int, vector<int>, decltype(first_free)> done_on_left(first_free), done_on_right(first_free);
_86
_86
for (int i = 0; i < k; ++i)
_86
left.push(i);
_86
_86
int boxes_left = n;
_86
int current_time = 0;
_86
_86
while (boxes_left > 0 || not right.empty() || not done_on_right.empty()) {
_86
_86
// prefer crossing right to left
_86
if (not right.empty()) {
_86
int worker = right.top();
_86
right.pop();
_86
_86
current_time += right_to_left(worker);
_86
_86
// this worker will be ready to rejoin the left queue
_86
time_free[worker] = current_time + put_down_box(worker);
_86
done_on_left.push(worker);
_86
_86
} else if (not left.empty() && boxes_left > 0) {
_86
_86
int worker = left.top();
_86
left.pop();
_86
_86
// this worker "claims" a box
_86
boxes_left -= 1;
_86
_86
current_time += left_to_right(worker);
_86
_86
// this worker will be ready to rejoin the right queue
_86
time_free[worker] = current_time + pick_up_box(worker);
_86
done_on_right.push(worker);
_86
_86
} else {
_86
current_time = min(
_86
done_on_right.empty() ? INT_MAX : time_free[done_on_right.top()],
_86
done_on_left.empty() ? INT_MAX : time_free[done_on_left.top()]
_86
);
_86
}
_86
_86
// let any workers who are done rejoin the respective queues
_86
while (not done_on_right.empty() && time_free[done_on_right.top()] <= current_time) {
_86
int worker = done_on_right.top();
_86
done_on_right.pop();
_86
_86
right.push(worker);
_86
}
_86
_86
while (not done_on_left.empty() && time_free[done_on_left.top()] <= current_time) {
_86
int worker = done_on_left.top();
_86
done_on_left.pop();
_86
_86
left.push(worker);
_86
}
_86
}
_86
_86
return current_time;
_86
}
_86
};

If you found this solution helpful, consider leaving a star!