90 likes | 146 Views
Problem Solving: Brute Force Approaches. Brute Force Approaches (aka Complete Search). Basic idea: try out everything to find the best. Sometimes, this is the only reasonable solution Given an unsorted list of numbers, find the max/min. Only option is to look at each number.
E N D
Brute Force Approaches (aka Complete Search) • Basic idea: try out everything to find the best. • Sometimes, this is the only reasonable solution • Given an unsorted list of numbers, find the max/min. • Only option is to look at each number. • Sometimes, the brute-force approach is good enough • Especially when sizes are not too large, or time is not an issue • e.g. if checking n! different options, if n is 3 or 4, it might be fine to enumerate them. • Often, the brute-force approach is the easiest to implement • Unless you expect time to be an issue (which it often is…), it’s a good way to start • Solving via brute force ensures you understand the problem and know a way to find a solution
Basic ways to approach brute force • Iterative vs. recursive • Iterative: loop through to generate all possible combinations • Sometimes will need many loops • Recursive: use “backtracking” to choose next, repeatedly • Generative vs. filtered • Generators: generate the possible answers – the good ones • Often a recursive definition is better, here • Filtered: generate all answers and choose valid ones
Iterative approaches • Loop through all options, testing each • Example: find all pairs of numbers where X is c times Y, and X and Y use are 5-digit numbers, using all from 0-9 • Multiple loops • Example: enumerate all subsets of 6 numbers from a larger collection; use 6 nested loops • Limit range of search • If x2+y2+z2 = C, then x, y, z must have absolute value < sqrt(C), etc. • Keep flag to stop loops early (pruning) • Generating all permutations • Example: For 8 moviegoers, what seating options in a row meet all of 20 conditions (setting limits about distance apart/near) • Subset-sum • Generate all subsets, then check those • n items, 2n possible subsets; possibly viable for n<=20
Example • Read numbers A, B C, each <= 10000. Find distinct x, y, z so that: • x+y+z = A • x*y*z = B • x2+y2+z2 = C • We can limit loops to [-100,100] for each, due to C • We can limit one of these to cube root of B, or [-22,22] at most • We can do fast checks to make sure x, y, z are distinct before doing calculations • Then, just have loops, and check answers.
Recursive search • Recursively search for all possible solutions to a problem • Key is to prune away invalid solutions quickly • Classical problem: 8 queens • Find the positions possible for arranging 8 queens on a chessboard so they can’t attack each other • First: note each column must have one queen, so can recurse that way • Check each row for that column to see if valid – if so, place and recurse (for each valid position) • Valid position means not at the same row or on same diagonal as a prior queen • Helps prune away large sections of search space. • Expanded problem: n-queens on larger board • Need faster (e.g. bitfield) storage to identify valid/invalid rows/diagonals. • Notice: 2n-1 left and 2n-1 right diagonals on an nxn board.
Tips to improve performance of brute force • Use short-circuiting of if statements to limit checks • Pruning: identify early when there is an infeasible branch • Remember that sometimes you can bound quality of a branch • Symmetries: Can drastically reduce the search space. • But, can involve a lot of overhead and complicate the code • Pre-compute: When some values can be known ahead of time, precompute and store. • Solve backward: Look at whether the inverse problem is faster • Optimize source code: • First, try to identify the “critical” code • (see next page)
Optimizing source code • Use a faster language: C++>Java>Python • Faster I/O: • C++: scanf/printf vs. cin/cout (scanf/printf don’t flush other) • Java: BufferedReader/BufferedWriter vs. Scanner/PrintStream • Use built-in fast stort (e.g. C++ algorithm::sort) • Access 2D arrays in row-major order (for cache coherency) • Use bit manipulations whenever possible • Use low-level structures when you know you don’t need advanced functionality • e.g. arrays vs. vectors, char[] vs. string • Do single allocation of array as a global • Locals avoid passing/copying • Dynamic allocation will take time • Iterative instead of recursive code when possible • Avoid repeated array access – store the data in a variable
Brute Force in Book • Book references – section 3.2 • Examples of basic problem solutions • Generating all permutations • Use the C++ next_permutation algorithm (iterative approach to generating permutations!). • Generating all subsets • Form an n-bit bitmask (integer), then iterate through numbers