NeFut Logo NeFut
Admin Login

Exploring Circular Dynamic Programming Techniques: Breaking Chains and Boundary Fixing

Published at: 2026-05-27 09:17 Last updated: 2026-06-10 09:26
#algorithm #Dynamic Programming #DP

Core Logic and Mathematical Principles

The essence of circular dynamic programming is to handle the end-to-end connectivity of topological structures. In a normal linear sequence, positions $1$ and $N$ are disconnected boundaries; however, in a circular structure, there exists an equivalent directed edge between positions $1$ and $N$, causing the state space to be geometrically closed.

For handling circular topologies, there are two mainstream hardcore dimensionality reduction mapping techniques:

  1. Breaking the Circle into a Chain (Doubling Method):

    • Geometric Mapping: Duplicate the original circular sequence of length $M$ and append it to the end of the original sequence, forming a linear sequence of length $2M$: $A[1 \text{ to } 2M]$.
    • Logical Equivalence: Any continuous segment of length $M$ in the original circular structure can uniquely correspond to an interval $[l, l + M - 1]$ in the doubled linear sequence (where $1 \text{ ≤ } l \text{ ≤ } M$).
    • Applicable Scenarios: Models such as interval DP and sliding window that require explicit enumeration of all possible continuous sub-intervals on the circle.
  2. Converting Boundary to Multiple DP (Boundary Fixing):

    • Geometric Mapping: Explicitly cut the circular edge between positions $1$ and $M$, degenerating it into a linear structure. To forcibly close the end-to-end constraints, multiple independent linear DPs must be performed by "enforcing boundary conditions".
    • Logical Equivalence: For constraints on adjacent positions (e.g., "two adjacent positions cannot be selected simultaneously"), either position $1$ is not selected (in which case the selection of position $M$ is irrelevant), or position $1$ must be selected (in which case position $M$ cannot be selected). These two boundary conditions exhaustively enumerate all valid topological states connected end-to-end.
    • Applicable Scenarios: Tree DP and linear sequence selection problems (e.g., maximum non-adjacent subset in a circle).

State Design and Algorithm Derivation

Taking the classic examples of "Circular Stone Merging" and "Circular Robbery (Maximum Non-Adjacent Subset)" as examples, we break down the state derivation.

1. Circular Interval DP (Breaking the Circle into a Chain)

$$f[l][r] = \min_{l \text{ ≤ } k < r} \bigg\{ f[l][k] + f[k+1][r] \bigg\} + (S[r] - S[l-1])$$

where the prefix sum array $S$ must be preprocessed to the boundary of $2M$.

$$\text{Ans} = \min_{1 \text{ ≤ } l \text{ ≤ } M} \bigg\{ f[l][l + M - 1] \bigg\}$$

2. Circular State Compression (Two Times DP Boundary Control)

Assuming the sequence length is $M$, adjacent positions cannot be selected simultaneously.


C++ Standard Source Code (NOIP Style)

The following code provides a complete implementation of circular stone merging (Doubling Method) and maximum non-adjacent profit (Two Times DP Method) in one program.

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

using namespace std;

const int MAXN = 405; // For Doubling, the array size must be doubled 2 * 200 = 400
const int INF = 0x3f3f3f3f;

int a[MAXN];
int s[MAXN];
int f_min[MAXN][MAXN];

// Array for linear DP circular cut model
int v[MAXN];
int dp[MAXN][2];

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int m;
    if (!(cin >> m)) return 0;

    // ==================== Model 1: Circular Stone Merging (Breaking into Chain) ====================
    for (int i = 1; i <= m; ++i) {
        cin >> a[i];
        a[i + m] = a[i]; // Core: Doubling sequence, mapping the circle to double length chain
    }

    int n = 2 * m;
    for (int i = 1; i <= n; ++i) {
        s[i] = s[i - 1] + a[i]; // Prefix sum boundary extended to 2M
    }

    // Interval DP Initialization
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            f_min[i][j] = (i == j) ? 0 : INF;
        }
    }

    // Standard interval DP topological sequence recursion
    for (int len = 2; len <= m; ++len) { // Fatal pitfall: The upper limit of the merged interval length is still M, not 2M!
        for (int l = 1; l <= n - len + 1; ++l) {
            int r = l + len - 1;
            int score = s[r] - s[l - 1];
            for (int k = l; k < r; ++k) {
                f_min[l][r] = min(f_min[l][r], f_min[l][k] + f_min[k + 1][r] + score);
            }
        }
    }

    // Horizontally scan the minimum value among all linear valid intervals of length M
    int ans_merge = INF;
    for (int l = 1; l <= m; ++l) {
        ans_merge = min(ans_merge, f_min[l][l + m - 1]);
    }


    // ==================== Model 2: Circular Maximum Non-Adjacent Profit (Two Times DP) ====================
    for (int i = 1; i <= m; ++i) {
        cin >> v[i];
    }

    // ---- First DP: Forcibly not selecting position 1 ----
    dp[1][0] = 0;
    dp[1][1] = -INF; // Block selection of 1
    for (int i = 2; i <= m; ++i) {
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
        dp[i][1] = dp[i - 1][0] + v[i];
    }
    int res1 = max(dp[m][0], dp[m][1]); // Position 1 not selected, position M can be either selected or not

    // ---- Second DP: Forcibly selecting position 1 ----
    dp[1][0] = -INF; // Block not selecting 1
    dp[1][1] = v[1];
    for (int i = 2; i <= m; ++i) {
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
        dp[i][1] = dp[i - 1][0] + v[i];
    }
    int res2 = dp[m][0]; // Fatal pitfall: Position 1 selected, position M must be in the unselected state (0)

    int ans_select = max(res1, res2);

    cout << ans_merge << " " << ans_select << "\n";

    return 0;
}

NOIP Practical Pitfall Guide

1. Out of Bounds Control for Interval Length $len$ When Breaking the Circle into a Chain

2. Illegal Overlap in Terminal State Updates During Two Times DP Boundary Control


Classic NOIP/Luogu Problems

1. Luogu P1880 [NOI1995] Stone Merging

2. Luogu P6064 [USACO05JAN] Naptime G

Original Source: local://15.2

[h] Back to Home