A company is planning to interview 2n people. Given the array costs where costs[i] = [aCost[i], bCost[i]], the cost of flying the i-th person to city a is aCost[i], and the cost of flying the i-th person to city b is bCost[i].
Return the minimum cost to fly every person to a city such that exactly n people arrive in each city.
Example 1:
Input: costs = [[10,20],[30,200],[400,50],[30,20]]
Output: 110Explanation:
The first person goes to city A for a cost of 10.
The second person goes to city A for a cost of 30.
The third person goes to city B for a cost of 50.
The fourth person goes to city B for a cost of 20.
The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each city.
Example 2:
Input: costs = [[259,770],[448,54],[926,667],[184,139],[840,118],[577,469]]
Output: 1859Example 3:
Input: costs = [[515,563],[451,713],[537,709],[343,819],[855,779],[457,60],[650,359],[631,42]]
Output: 3086Constraints:
2 * n == costs.length2 <= costs.length <= 100costs.length is even.1 <= aCost[i], bCost[i] <= 1000Before attempting this problem, you should be comfortable with:
We need to send exactly n people to city A and n people to city B, minimizing total cost. For each person, we have two choices: send them to A or B. We can explore all possible assignments using recursion, tracking how many slots remain for each city.
i, try sending them to city A (if slots remain) and to city B (if slots remain).i == len(costs)), return 0.class Solution:
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
n = len(costs) // 2
def dfs(i, aCount, bCount):
if i == len(costs):
return 0
res = float("inf")
if aCount > 0:
res = costs[i][0] + dfs(i + 1, aCount - 1, bCount)
if bCount > 0:
res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1))
return res
return dfs(0, n, n)Where is the size of the array .
The recursive solution has overlapping subproblems because the same state (remaining slots for A and B) can be reached through different paths. We can use memoization to cache results and avoid redundant computation.
dp[aCount][bCount] to store the minimum cost when aCount slots remain for city A and bCount slots remain for city B.i can be derived from aCount + bCount since the total remaining equals 2n - i.class Solution:
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
n = len(costs) // 2
dp = [[-1] * (n + 1) for _ in range(n + 1)]
def dfs(i, aCount, bCount):
if i == len(costs):
return 0
if dp[aCount][bCount] != -1:
return dp[aCount][bCount]
res = float("inf")
if aCount > 0:
res = costs[i][0] + dfs(i + 1, aCount - 1, bCount)
if bCount > 0:
res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1))
dp[aCount][bCount] = res
return res
return dfs(0, n, n)Where is the half of the size of the array .
Instead of recursion with memoization, we can build the solution iteratively. We fill a table where dp[aCount][bCount] represents the minimum cost to assign the first aCount + bCount people such that aCount go to city A and bCount go to city B.
dp[0][0] = 0 (no people assigned, zero cost).(aCount, bCount):i = aCount + bCount.aCount > 0, consider the option of sending person i-1 to city A.bCount > 0, consider the option of sending person i-1 to city B.dp[n][n].class Solution:
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
n = len(costs) // 2
dp = [[0] * (n + 1) for _ in range(n + 1)]
for aCount in range(n + 1):
for bCount in range(n + 1):
i = aCount + bCount
if i == 0:
continue
dp[aCount][bCount] = float("inf")
if aCount > 0:
dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0])
if bCount > 0:
dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1])
return dp[n][n]Where is the half of the size of the array .
Looking at the bottom-up recurrence, each cell dp[aCount][bCount] only depends on dp[aCount-1][bCount] and dp[aCount][bCount-1]. We can reduce space by using a 1D array and carefully updating it in the right order.
dp of size n+1.(aCount, bCount) pairs in the same order as before.dp[bCount] before overwriting.dp[bCount] using the temporary variable (for the city A option) and dp[bCount-1] (for the city B option).dp[n].class Solution:
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
n = len(costs) // 2
dp = [0] * (n + 1)
for aCount in range(n + 1):
for bCount in range(n + 1):
i = aCount + bCount
if i == 0:
continue
tmp = dp[bCount]
dp[bCount] = float("inf")
if aCount > 0:
dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0])
if bCount > 0:
dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1])
return dp[n]Where is the half of the size of the array .
For each person, the "cost difference" cost[B] - cost[A] tells us how much extra we pay to send them to city B instead of A. A negative difference means B is cheaper. If we sort by this difference, the first half of people have the smallest (most negative) differences, meaning they benefit most from going to city B.
(cost[B] - cost[A], cost[A], cost[B]).n people (smallest differences) to city B.n people to city A.class Solution:
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
diffs = []
for c1, c2 in costs:
diffs.append([c2 - c1, c1, c2])
diffs.sort()
res = 0
for i in range(len(diffs)):
if i < len(diffs) // 2:
res += diffs[i][2]
else:
res += diffs[i][1]
return resWe can simplify the greedy approach by sorting the original array directly by cost[B] - cost[A] without creating extra tuples. After sorting, the first n entries favor city B, and the last n favor city A.
costs array by cost[1] - cost[0] (ascending).n people, add their city B cost.n people, add their city A cost.The greedy approach requires sorting by cost[B] - cost[A] to determine which people benefit most from going to city B. A common mistake is sorting by cost[A] - cost[B] or by individual costs rather than the difference. This leads to suboptimal assignments because you are not correctly identifying the relative advantage of each city for each person.
The problem requires exactly n people to go to city A and n people to go to city B. A greedy approach that simply sends each person to their cheaper city without tracking counts will likely result in an unbalanced distribution. Always ensure your solution enforces the constraint that exactly half go to each city.
In the bottom-up DP approach, the person index i is derived from aCount + bCount. A common error is using i instead of i - 1 when accessing the costs array, or incorrectly computing which person corresponds to a given state. This leads to accessing wrong cost values or array index out of bounds errors.