Greedy · 28 of 35
Picking Up Chicks
Get k chicks into the barn on time with the fewest lifts over slow chicks, by saving the fast chicks closest to the barn first.
- Simple way
- time O(2^n * n^2)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
This is a Google Code Jam problem. n chicks stand on a narrow road at positions x[0] < x[1] < ..., all running toward a barn at position b. Chick i runs at speed v[i]. A chick cannot pass the chick in front of it; it has to slow down and walk behind it.
You may pick up a slow chick and put it down just behind the faster chick, which lets the fast one pass. That is one swap, and it takes no time. You need at least k chicks in the barn within t seconds. Give back the fewest swaps, or say it is impossible.
A story to remember it
Picture it
Barn at 10, 2 seconds. Each bar runs from a chick's start to where it could get alone. Chicks 0, 2 and 5 reach the barn line, the others do not.
- done
- rejected
Examples
No swaps needed
- In
k = 3, b = 10, t = 5, x = [0, 2, 5, 6, 7], v = [1, 1, 1, 1, 4]- Out
0
The three chicks at 5, 6 and 7 can make it and nobody slow is in front of them.
Two swaps
- In
k = 3, b = 10, t = 5, x = [0, 2, 3, 5, 7], v = [2, 1, 1, 1, 4]- Out
2
The chicks at 5 and 7 make it for free. The chick at 0 is fast enough but the slow chicks at 2 and 3 are in front, so it needs 2 swaps.
The walkthrough road
- In
k = 3, b = 10, t = 2, x = [0, 2, 4, 5, 7, 8], v = [5, 1, 4, 2, 1, 2]- Out
5
Save chick 5 for free, chick 2 for 2 swaps, and chick 0 for 3 swaps. With k = 2 the answer would be 2.
Impossible
- In
k = 3, b = 10, t = 5, x = [0, 1, 2, 3, 4], v = [1, 1, 1, 1, 1]- Out
IMPOSSIBLE
Even alone, the best chick only reaches 9 in time. No swaps can fix that.
Way 1: the simple way
First mark which chicks are fast enough alone: chick i can make it if x[i] + v[i] * t >= b. Slow chicks are never worth saving. Then try every group of k fast chicks. A chosen chick needs one swap for every slow chick in front of it, so add those up and keep the smallest total.
class Solution {
private long best;
// returns the fewest swaps, or -1 for IMPOSSIBLE; chicks are sorted by position
public long minSwaps(int k, int b, int t, int[] x, int[] v) {
int n = x.length;
boolean[] fast = new boolean[n];
for (int i = 0; i < n; i++) fast[i] = x[i] + (long) v[i] * t >= b;
best = Long.MAX_VALUE;
choose(0, k, fast, new boolean[n]);
return best == Long.MAX_VALUE ? -1 : best;
}
private void choose(int i, int left, boolean[] fast, boolean[] picked) {
if (left == 0) {
long swaps = 0;
for (int c = 0; c < fast.length; c++) {
if (!picked[c]) continue;
for (int d = c + 1; d < fast.length; d++) {
if (!fast[d]) swaps++; // a slow chick in front of a saved chick
}
}
best = Math.min(best, swaps);
return;
}
if (i == fast.length) return;
if (fast[i]) {
picked[i] = true;
choose(i + 1, left - 1, fast, picked);
picked[i] = false;
}
choose(i + 1, left, fast, picked);
}
}How long it takes: up to 2^n groups, and each one is counted in O(n^2), so O(2^n * n^2). Extra room: the flags and the recursion, O(n).
Way 2: the clever way
Two facts make this easy.
- A fast chick only needs swaps for slow chicks in front of it. If a fast chick is stuck behind another fast chick, the one in front arrives in time, so the one behind does too.
- A fast chick closer to the barn never has more slow chicks in front of it than a fast chick further back. So the cheapest
kchicks to save are thekfast chicks closest to the barn.
So walk from the barn end backward. Count the slow chicks you pass. Each fast chick you meet costs that count in swaps. Stop after k saved chicks.
Walk back from the barn, counting slow chicks
01 / 09
Six chicks on the road, the barn is at 10, and there are 2 seconds. Each bar shows how far a chick could run in 2 seconds if nobody were in its way. The line is the barn.
- need saved
- 3
- looking now
- done
- answer
- rejected
- ignored
class Solution {
// returns the fewest swaps, or -1 for IMPOSSIBLE; chicks are sorted by position
public long minSwaps(int k, int b, int t, int[] x, int[] v) {
int saved = 0, slowAhead = 0;
long swaps = 0;
for (int i = x.length - 1; i >= 0 && saved < k; i--) {
if (x[i] + (long) v[i] * t >= b) { // fast enough on an empty road
swaps += slowAhead; // hop over every slow chick in front
saved++;
} else {
slowAhead++; // blocks every fast chick behind it
}
}
return saved == k ? swaps : -1;
}
}How long it takes: one walk, O(n). Extra room: three counters, O(1).
Watch out for
- Stop as soon as
kchicks are saved. Slow chicks further back do not matter. v[i] * tcan be large. Compute it as along.- A chick that lands exactly on the barn at time
tcounts, so the check is>=. k = 0needs 0 swaps.
What interviewers ask next
- Why is one swap per slow chick enough and also needed? A fast chick arrives by
tand the slow one in front arrives aftert, so the fast one must catch it before the barn and must be lifted past it exactly once. - Why closest fast chicks first? The count of slow chicks in front only grows as you walk back, so any other choice of
kfast chicks costs at least as much. - What if chicks are not given in road order? Sort them by position first, which makes it
O(n log n). - What if each swap had a different price? The greedy breaks. You would need dynamic programming over the chicks from the barn end.
Remember this
Grown-up words: the narrow road is a single lane where order is kept, "can make it alone" is a reachability check x + v * t >= b, the walk from the barn end is a reverse scan, and charging each chick the slow chicks ahead is counting inversions with a running counter.