Inverse Dynamic Programming for Backpack Deletion
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;
}