Your brute force is too slow — it's an optimization problem
If you wrote a loop over itertools.permutations, itertools.combinations, or a
product of choices to find the best option, and it grinds to a halt as the
input grows, you don't have a performance bug — you have an optimization
problem. The fix is not a faster loop; it's to model the problem and hand it to
a solver like quicopt, which prunes the search instead of enumerating it.
Recognize the pattern
The naive code almost always looks like one of these:
# ordering / sequencing -> exponential (n!)
for order in itertools.permutations(items): ...
# pick a subset -> exponential (2^n)
for pick in itertools.product([0, 1], repeat=n): ...
# split / allocate -> exponential or a coarse grid
for a in range(N):
for b in range(N - a): ...
Each of these is a known problem with a compact model. Instead of enumerating,
you declare variables, constraints and an objective, and call solve().
The fix, concretely
Assigning N workers to N tasks by trying every permutation is O(n!). As a MILP
it is a few lines and comes back proven optimal:
from ortools.math_opt.python import mathopt
from quicopt import Client
cost = [[9,11,14,11,7],[6,15,13,13,10],[12,13,6,8,8],[11,9,10,12,9],[7,12,14,10,14]]
N = len(cost)
model = mathopt.Model(name="assignment")
x = [[model.add_binary_variable(name=f"x_{w}_{t}") for t in range(N)] for w in range(N)]
for w in range(N):
model.add_linear_constraint(sum(x[w][t] for t in range(N)) == 1)
for t in range(N):
model.add_linear_constraint(sum(x[w][t] for w in range(N)) == 1)
model.minimize(sum(cost[w][t] * x[w][t] for w in range(N) for t in range(N)))
print(Client("https://try.quicoptapi.pgi.fz-juelich.de").solve(model).display)
├── status: optimal ├── feasible: true ├── objective: 38.0 ├── x: x_0_0=0, x_0_1=0, x_0_2=0, x_0_3=0, x_0_4=1, x_1_0=1, … (25 variables) └── solve_time: 0.0117 s
Find your problem
| Your brute force looks like… | It's probably… | Guide |
|---|---|---|
| permutations of stops / a tour | Traveling salesman | TSP |
| routes for several vehicles | Vehicle routing | VRP |
| matching A's to B's one-to-one | Assignment | Assignment |
| pick items under a budget/limit | Knapsack | Knapsack |
| fewest sets/options covering everything | Set cover | Set cover |
| pack items into fewest bins | Bin packing | Bin packing |
| split jobs across machines/workers | Scheduling | Scheduling · Shifts |
| color / assign without conflicts | Graph coloring | Graph coloring |
| split a graph in two | Max-cut | Max-cut |
| divide a budget / resources | Allocation | Resource allocation |
Next
- Browse every guide by problem class: Guides
- Set up the client and solve your first model: Getting started
Not sure which one fits?
Tell us what you're optimizing — paste your slow loop — and we'll point you at the right model.
Frequently asked questions
How do I know it's an optimization problem?
If you're looping over permutations, combinations, or a product of choices to find the best one, and it slows to a crawl as inputs grow, it's an optimization problem — a solver prunes that search instead of walking it.
Won't a solver be overkill for small inputs?
No — the model is a few lines and solves the small cases instantly too. The difference is it keeps working when the input grows past what brute force can handle.
Is quicopt free to use?
Yes — pip install quicopt and your first call sets up a free key, no license.