Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Inverse Dynamic Programming for Backpack Deletion

Tech 1

In standard 0/1 knapsack problems, the objective is often to determine the number of ways to fill a specific capacity by adding items. However, challlenges arise when we need to compute the number of valid combinations after excluding a specific item from an already calculated set.

Let $F[j]$ represent the number of ways to achieve capacity $j$ using all items, and $G[j]$ represent the number of ways to achieve capacity $j$ excluding a specific item $x$ with weight $w_x$. The relationship between these states is defined by the transition equation:

$$F[j] = G[j] + G[j - w_x]$$

Consequently, we can derive the state excluding item $x$ by rearranging the formula:

$$G[j] = F[j] - G[j - w_x]$$

To implement this, we first compute the global DP array $F$ using the standard knapsack approach (iterating capacity in descending order). To exclude item $x$, we clone the $F$ array into a temporary buffer. We then iterate the capacity $j$ from $w_x$ to the maximum capacity $M$ in ascending order. This ascending order is crucial because when calculating $G[j]$, we require the value of $G[j - w_x]$, which must already have been computed in the current pass (effectively acting as the 'excluded' state for the smaller capacity).

The following C++ implementation demonstrates this approach, calculating the number of combinations modulo 10 for each item removal scenario:

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int MAX_DIM = 2050;

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

    int item_count, capacity_limit;
    if (!(cin >> item_count >> capacity_limit)) return 0;

    vector<int> weights(item_count + 1);
    for (int i = 1; i <= item_count; ++i) {
        cin >> weights[i];
    }

    // dp[j] stores combinations for capacity j using all items
    int total_dp[MAX_DIM] = {0};
    total_dp[0] = 1;

    // Forward DP: accumulate contributions from all items
    for (int i = 1; i <= item_count; ++i) {
        int w = weights[i];
        for (int j = capacity_limit; j >= w; --j) {
            total_dp[j] += total_dp[j - w];
            if (total_dp[j] >= 10) total_dp[j] -= 10;
        }
    }

    // For each item, calculate the result excluding it
    for (int i = 1; i <= item_count; ++i) {
        int current_dp[MAX_DIM];
        memcpy(current_dp, total_dp, sizeof(total_dp));
        int w = weights[i];

        // Inverse DP: remove contribution of the specific item
        for (int j = 1; j <= capacity_limit; ++j) {
            if (j >= w) {
                current_dp[j] -= current_dp[j - w];
                // Normalize negative values modulo 10
                while (current_dp[j] < 0) current_dp[j] += 10;
            }
            cout << current_dp[j];
        }
        cout << '\n';
    }

    return 0;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.