You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化n≤20的按钮翻转问题回溯算法运行时长?

Optimizing Backtracking for the Button Flip Problem

Great job getting your backtracking solution up and running for the button flip problem! Let's dive into some targeted optimizations that can slash that runtime for n=20 from a minute down to just seconds.

Key Observations to Build Optimizations On

First, let's recap your solid existing pruning step: you stop exploring a branch if the row above the current position has mismatched states, since you can't go back to fix it later. We can build on this with smarter constraints and faster operations.


1. Fix First Row Enumeration (Game-Changer for Runtime)

Instead of enumerating every single button's press/no-press state across the entire grid, only enumerate all possible states of the first row (2^n possibilities, which for n=20 is ~1 million—way better than 2^40!). Here's why this works:

  • Once the first row's press state is fixed, every button in the second row is completely determined: if a button in the first row is still pressed (O), you must press the button directly below it to flip it (since you can't go back to the first row anymore).
  • Repeat this logic for every subsequent row: each row's press state is determined entirely by the state of the row above it.
  • After deriving all rows, just check if the final row is all un-pressed (#). If yes, calculate the total number of presses and keep track of the minimum.

This cuts the search space from exponential in n² to exponential in n—an enormous reduction for n=20.

2. Replace Array Operations with Bitwise Calculations

Since n ≤ 20, we can represent each row's state as a 32-bit integer (where each bit represents a button: 0 = #, 1 = O). Pressing a button translates to XOR-ing with a precomputed bitmask, which is way faster than modifying a 2D array.

For example:

  • Precompute a mask for each column col in a row: this mask includes bits for col, col-1 (if valid), and col+1 (if valid) (since pressing a button flips itself and left/right neighbors).
  • Precompute another mask for the row below: pressing column col flips the same column in the row below, so this mask is just 1 << col.

With bitwise operations, state updates and checks happen in nanoseconds instead of microseconds, which adds up quickly for large n.

3. Early Termination with Minimum Press Tracking

Keep track of the smallest number of presses you've found so far that solves the problem. As you derive each row:

  • If the total number of presses used already exceeds this minimum, immediately abandon this branch—there's no need to keep calculating, since it can't produce a better solution.
  • Initialize this minimum to a high value (like n²) and update it whenever you find a valid solution with fewer presses.

4. Precompute All Press Masks Upfront

Avoid recalculating the bitmasks for each press every time. Precompute two arrays once at the start:

  • row_masks[col]: The bitmask to XOR with the current row when pressing column col.
  • below_masks[col]: The bitmask to XOR with the row below when pressing column col.

This saves redundant calculations during the core search loop.

5. Parallelize the First Row Enumeration

Since each first-row state is independent of the others, you can split the 2^n first-row possibilities into chunks and process them in parallel using multiple threads. Most modern CPUs have 4+ cores, so this can cut runtime roughly in half (or more, depending on your CPU).


Putting It All Together

Here's a quick outline of how to adjust your existing backtracking approach:

  1. Precompute row_masks and below_masks for all columns.
  2. Iterate over every possible first-row press state (from 0 to 2^n - 1).
  3. For each first-row state:
    a. Calculate the initial grid state (starting from the input array) after applying the first-row presses.
    b. Derive each subsequent row's press state based on the row above's current state.
    c. Count the total presses as you go—if it exceeds the current minimum, break early.
    d. After processing all rows, check if the final row is all #. If yes, update the minimum press count and save the solution.
  4. Once all first-row states are processed, output the solution with the minimum presses.

This approach retains the core backtracking logic but narrows the search space drastically and speeds up each iteration with bitwise operations.

内容的提问来源于stack exchange,提问作者mille

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:31:35