NeFut Logo NeFut
Admin Login

Efficient State Space Search and Pruning Strategies

Published at: 2026-05-29 00:44 Last updated: 2026-06-06 13:04
#C++ #Tutorial

Core Logic and Mathematical Principles

The essence of search is traversing the state space tree. Faced with the exponential growth of the state space, the underlying logic of pruning is to terminate invalid branches early, theoretically reducing the search complexity from $O(k^N)$ to a practically feasible scale.


State Design and Algorithm Derivation

Taking the classic problem of "Birthday Cake" (NOI1999 / Luogu P1731) as an example. The problem requires building a cake with a total volume of $N$ in $M$ layers, with radius $R$ and height $H$ strictly decreasing from bottom to top, seeking to minimize the surface area.

1. State Design

The search state is determined by the current layer number, current volume, current surface area, and the radius and height of the previous layer. Define the DFS function state: dfs(dep, v, s, last_r, last_h). Here, dep is the current layer being searched (from bottom to top, with the bottom being layer $M$ and the top being layer $1$).

2. Bound Derivation

For the $i$-th layer, the volume and height must be greater than or equal to the minimum volume and height of all layers above it.

$$R_i \le \min\left(\lfloor \sqrt{N - v} \rfloor, last_r - 1\right)$$

$$H_i \le \min\left(\lfloor \frac{N - v}{R_i^2} \rfloor, last_h - 1\right)$$

3. Pruning Strategy Derivation

$$s + \frac{2(N - v)}{last_r} \ge ans \implies \text{Backtrack}$$


C++ Standard Source Code

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>

int N, M;
int ans = 2e9;
int min_v[25], min_s[25];

// State: dep(current layer), v(accumulated volume), s(accumulated surface area), r(previous layer radius), h(previous layer height)
void dfs(int dep, int v, int s, int r, int h) {
    if (dep == 0) {
        if (v == N) {
            ans = std::min(ans, s);
        }
        return;
    }

    // Feasibility Pruning: Current volume + minimum volume of the top layer > target volume
    if (v + min_v[dep] > N) return;

    // Optimality Pruning 1: Current surface area + minimum lateral area of the top layer >= known optimal solution
    if (s + min_s[dep] >= ans) return;

    // Optimality Pruning 2: Use mathematical inequality to estimate the lower bound of future costs
    if (s + 2 * (N - v) / r >= ans) return;

    // Bound Pruning: Enumerate from bottom to top, prioritizing larger sizes (optimizing search order)
    int max_r = std::min(static_cast<int>(std::sqrt(N - v)), r - 1);
    for (int cur_r = max_r; cur_r >= dep; --cur_r) {
        if (dep == M) {
            s = cur_r * cur_r; // The base area of the cake is counted once at layer M
        }

        int max_h = std::min((N - v) / (cur_r * cur_r), h - 1);
        for (int cur_h = max_h; cur_h >= dep; --cur_h) {
            // Critical pitfall: Ensure that the base area is only included in special cases or at the first layer when recursively passing s; here only accumulate lateral area
            dfs(dep - 1, v + cur_r * cur_r * cur_h, s + 2 * cur_r * cur_h, cur_r, cur_h);
        }
    }
}

int main() {
    // Improve I/O efficiency to prevent timeout with large data volumes
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    if (!(std::cin >> N >> M)) return 0;

    // Preprocess prefix sums to provide boundary data for pruning
    for (int i = 1; i <= M; ++i) {
        min_v[i] = min_v[i - 1] + i * i * i;
        min_s[i] = min_s[i - 1] + 2 * i * i;
    }

    // Initial upper limit setting: Theoretical maximum radius and height cannot exceed N
    dfs(M, 0, 0, N, N);

    if (ans == 2e9) {
        std::cout << 0 << "\n";
    } else {
        std::cout << ans << "\n";
    }

    return 0;
}

NOIP Practical Pitfall Guide

  1. Search Order Reversal Leading to Pruning Failure In the absence of dependency relationships, prioritize enumerating decisions with "fewer branches" or "higher costs". For example, in combinatorial optimization or pruning problems, enumerating the for loop from large to small (from max_r to dep) allows deeper states to approach the global optimal solution $ans$ earlier, thereby increasing the likelihood of triggering subsequent pruning $s + min_s[dep] >= ans$. Enumerating from small to large can lead to severe left-side expansion of the search tree.
  2. Integer Truncation and Estimation Function Overflow When performing mathematical scaling for optimality pruning, expressions like s + 2 * (N - v) / r may cause downward rounding if integer division is used directly, leading to an underestimated lower bound. In extreme cases, if it is just at the edge of the optimal solution, this error may lead to incorrect pruning (killing the correct solution). Additionally, when calculating cubes and squares, if the range of $N$ increases (as in some variant problems), failure to convert to long long may cause data overflow, resulting in feasibility pruning failure and triggering infinite loops.

Classic NOIP/Luogu Real Questions

1. Luogu P1120 Little Sticks

2. Luogu P1434 Skiing

Original Source: local://4.1

[h] Back to Home