🧠
Brute Force (Pure Recursion / Nested Loops / etc.)
💡 This approach tries every possible way to assign people to cities, which is impractical but helps understand the problem's complexity and why optimization is needed.
Intuition
Try all combinations of sending n people to city A and n people to city B, calculate total cost for each, and pick the minimum.
Algorithm
- Define a recursive function that tracks current index, count of people sent to city A, and total cost so far.
- At each person, if city A quota not full, recurse by sending them to city A.
- If city B quota not full, recurse by sending them to city B.
- Return the minimum cost from all recursive calls.
💡 The recursion tree grows exponentially because each person has two choices, and we must keep track of counts to ensure balanced assignment.
def twoCitySchedCost(costs):
n = len(costs) // 2
memo = {}
def dfs(i, a_count):
if i == len(costs):
return 0
if (i, a_count) in memo:
return memo[(i, a_count)]
b_count = i - a_count
res = float('inf')
if a_count < n:
res = min(res, costs[i][0] + dfs(i+1, a_count+1))
if b_count < n:
res = min(res, costs[i][1] + dfs(i+1, a_count))
memo[(i, a_count)] = res
return res
return dfs(0, 0)
# Example usage
if __name__ == '__main__':
costs = [[10,20],[30,200],[400,50],[30,20]]
print(twoCitySchedCost(costs))
Line Notes
n = len(costs) // 2Calculate half the number of people to know how many must go to each city
memo = {}Initialize memo dictionary to cache results of subproblems and avoid recomputation
def dfs(i, a_count):Define recursive function with current index and count of people sent to city A
if i == len(costs):Base case: all people assigned, cost is zero from here
if (i, a_count) in memo:Check if result for this state is already computed to save time
b_count = i - a_countCalculate how many people have been assigned to city B so far
res = float('inf')Initialize result to infinity to find minimum cost
if a_count < n:If city A quota not full, try assigning current person to city A
if b_count < n:If city B quota not full, try assigning current person to city B
memo[(i, a_count)] = resStore computed result in memo for future reference
return resReturn minimum cost for current state
import java.util.*;
public class Solution {
public int twoCitySchedCost(int[][] costs) {
int n = costs.length / 2;
Map<String, Integer> memo = new HashMap<>();
return dfs(costs, 0, 0, n, memo);
}
private int dfs(int[][] costs, int i, int aCount, int n, Map<String, Integer> memo) {
if (i == costs.length) return 0;
String key = i + "," + aCount;
if (memo.containsKey(key)) return memo.get(key);
int bCount = i - aCount;
int res = Integer.MAX_VALUE;
if (aCount < n) {
res = Math.min(res, costs[i][0] + dfs(costs, i + 1, aCount + 1, n, memo));
}
if (bCount < n) {
res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, n, memo));
}
memo.put(key, res);
return res;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[][] costs = {{10,20},{30,200},{400,50},{30,20}};
System.out.println(sol.twoCitySchedCost(costs));
}
}
Line Notes
int n = costs.length / 2;Calculate half the number of people for city quotas
Map<String, Integer> memo = new HashMap<>();Use memoization to cache results of subproblems
return dfs(costs, 0, 0, n, memo);Start recursion from first person with zero assigned to city A
if (i == costs.length) return 0;Base case: all people assigned, no additional cost
String key = i + "," + aCount;Create unique key for memoization based on current state
if (memo.containsKey(key)) return memo.get(key);Return cached result if available
int bCount = i - aCount;Calculate how many people assigned to city B so far
int res = Integer.MAX_VALUE;Initialize result to max value to find minimum cost
if (aCount < n)Only assign to city A if quota not full
if (bCount < n)Only assign to city B if quota not full
memo.put(key, res);Store computed result in memo
return res;Return minimum cost for current state
#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>
#include <algorithm>
using namespace std;
class Solution {
unordered_map<string, int> memo;
int n;
int dfs(const vector<vector<int>>& costs, int i, int aCount) {
if (i == costs.size()) return 0;
string key = to_string(i) + "," + to_string(aCount);
if (memo.count(key)) return memo[key];
int bCount = i - aCount;
int res = INT_MAX;
if (aCount < n) {
res = min(res, costs[i][0] + dfs(costs, i + 1, aCount + 1));
}
if (bCount < n) {
res = min(res, costs[i][1] + dfs(costs, i + 1, aCount));
}
memo[key] = res;
return res;
}
public:
int twoCitySchedCost(vector<vector<int>>& costs) {
n = costs.size() / 2;
return dfs(costs, 0, 0);
}
};
int main() {
Solution sol;
vector<vector<int>> costs = {{10,20},{30,200},{400,50},{30,20}};
cout << sol.twoCitySchedCost(costs) << endl;
return 0;
}
Line Notes
int n;Store half the number of people as class member for quota checks
unordered_map<string, int> memo;Memoize subproblem results to avoid recomputation
int dfs(const vector<vector<int>>& costs, int i, int aCount)Recursive function with current index and city A count
if (i == costs.size()) return 0;Base case: all people assigned, no cost left
string key = to_string(i) + "," + to_string(aCount);Create unique key for memoization
if (memo.count(key)) return memo[key];Return cached result if available
int bCount = i - aCount;Calculate how many assigned to city B
int res = INT_MAX;Initialize result to max int to find minimum
if (aCount < n)Assign to city A only if quota allows
if (bCount < n)Assign to city B only if quota allows
memo[key] = res;Store computed result
return res;Return minimum cost
var twoCitySchedCost = function(costs) {
const n = costs.length / 2;
const memo = new Map();
function dfs(i, aCount) {
if (i === costs.length) return 0;
const key = i + ',' + aCount;
if (memo.has(key)) return memo.get(key);
const bCount = i - aCount;
let res = Infinity;
if (aCount < n) {
res = Math.min(res, costs[i][0] + dfs(i + 1, aCount + 1));
}
if (bCount < n) {
res = Math.min(res, costs[i][1] + dfs(i + 1, aCount));
}
memo.set(key, res);
return res;
}
return dfs(0, 0);
};
// Example usage
console.log(twoCitySchedCost([[10,20],[30,200],[400,50],[30,20]]));
Line Notes
const n = costs.length / 2;Calculate half the number of people for city quotas
const memo = new Map();Memoize results of recursive calls to optimize
function dfs(i, aCount)Recursive function with current index and city A count
if (i === costs.length) return 0;Base case: all people assigned, no cost left
const key = i + ',' + aCount;Create unique key for memoization
if (memo.has(key)) return memo.get(key);Return cached result if available
const bCount = i - aCount;Calculate how many assigned to city B
let res = Infinity;Initialize result to infinity to find minimum
if (aCount < n)Assign to city A only if quota not exceeded
if (bCount < n)Assign to city B only if quota not exceeded
memo.set(key, res);Store computed result
return res;Return minimum cost
TimeO(2^(2n)) without memoization, reduced to O(n^2) states with memoization
SpaceO(n^2) due to memoization storage
Each person has two choices, leading to 2^(2n) possibilities. Memoization reduces the number of unique states to O(n^2) because the state is defined by index and count of city A assignments. However, this is still exponential in input size and impractical for large n.
💡 For n=10, this means about 2^20 calls without memoization, which is huge; memoization helps but still too slow for large inputs.
Interview Verdict: TLE / Use only to introduce
This approach is too slow for large inputs but is essential to understand the problem's complexity and motivate greedy solutions.