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

带特殊物品的扩展Knapsack问题算法设计咨询

Alright, let's tackle this extended knapsack problem with regular and special items (where you can pick at most S special items). I'll walk through a dynamic programming approach that's a straightforward extension of the classic 0-1 knapsack, with clear state definitions and transitions.

Problem Recap

First, let's align on the exact problem:

  • We have N items, each with weight, value, and a boolean isSpecial flag.
  • We need to select a subset of items such that:
    1. Total weight doesn't exceed the knapsack's capacity W (I’ll use W as the standard capacity variable here).
    2. We pick no more than S special items.
  • Our goal is to maximize the total value of the selected items.

Core Dynamic Programming Approach

The classic 0-1 knapsack uses a DP array to track maximum value for each possible weight. Here, we add an extra dimension to track how many special items we’ve picked so far—this lets us enforce the "at most S special items" constraint cleanly.

State Definition

Let’s define dp[s_count][weight] as the maximum value achievable by selecting:

  • Exactly s_count special items (0 ≤ s_count ≤ S)
  • With a total weight ≤ weight (0 ≤ weight ≤ W)

We’ll initialize this array with -infinity (to mark unreachable states) except for dp[0][0] = 0—this is our base case: zero items selected, zero weight, zero value.

State Transitions

For each item, we update the DP array based on whether it’s a regular or special item. Important: We iterate backwards through weight (and s_count for special items) to avoid reusing the same item multiple times—this is standard practice for 0-1 knapsack problems.

  1. Regular Item (isSpecial = false)
    For every possible count of special items we’ve already picked (s_count), we can choose to take or skip the item. Taking it doesn’t change our special item count, so we update the same s_count row:

    dp[s_count][w] = max(dp[s_count][w], dp[s_count][w - item.weight] + item.value)
    

    This is identical to the classic 0-1 knapsack transition.

  2. Special Item (isSpecial = true)
    We can only take this item if we haven’t hit the S limit yet. For each s_count < S, taking the item moves us to s_count + 1 special items, so we update the next row in the DP table:

    dp[s_count + 1][w] = max(dp[s_count + 1][w], dp[s_count][w - item.weight] + item.value)
    

Final Calculation

After processing all items, the answer is the maximum value across all valid states. That means checking every dp[s_count][w] where 0 ≤ s_count ≤ S and 0 ≤ w ≤ W—this covers all valid combinations of special items and total weight.

Full Pseudocode

Here’s a concrete implementation outline to make this tangible:

def extended_knapsack(W, S, items):
    # Initialize DP table: (S+1) rows (0 to S special items) x (W+1) columns (0 to W weight)
    dp = [[-float('inf')] * (W + 1) for _ in range(S + 1)]
    dp[0][0] = 0  # Base case: no items, no weight, no value

    for item in items:
        weight, value, is_special = item['weight'], item['value'], item['isSpecial']
        # Iterate backwards to prevent reusing the same item multiple times
        for s in range(S, -1, -1):
            for w in range(W, weight - 1, -1):
                if not is_special:
                    # Update same s_count row (no change to special item count)
                    if dp[s][w - weight] + value > dp[s][w]:
                        dp[s][w] = dp[s][w - weight] + value
                else:
                    # Only update if we can take one more special item
                    if s < S:
                        if dp[s][w - weight] + value > dp[s + 1][w]:
                            dp[s + 1][w] = dp[s][w - weight] + value

    # Find the maximum value across all valid states
    max_val = 0
    for s in range(S + 1):
        current_max = max(dp[s])
        if current_max > max_val:
            max_val = current_max
    return max_val

Key Notes & Edge Cases

  • Space Optimization: If memory is tight, you can use two 1D arrays (prev_dp and curr_dp) instead of a 2D array. Since each update only depends on the previous state, this cuts space from O(S*W) to O(W).
  • Edge Case: S=0: This reduces to the classic 0-1 knapsack—our code handles this automatically, as we won’t process any special item transitions.
  • Edge Case: All Items Are Special: Now it’s a knapsack where you can pick at most S items (with a weight constraint)—our code handles this by limiting transitions to s_count < S.
  • Time Complexity: O(NSW) — this is efficient enough for most practical cases (e.g., N up to 1000, S up to 100, W up to 10000).

Quick Example Walkthrough

Let’s test with a small scenario:

  • Knapsack capacity W=10, max special items S=1
  • Items:
    1. Regular: weight=5, value=10
    2. Special: weight=6, value=15
    3. Regular: weight=3, value=4

Processing item 1 (regular):

  • For s=0, we update dp[0][5] to 10 and dp[0][10] to 20.

Processing item 2 (special):

  • For s=0, we update dp[1][6] to 15 (since taking the special item uses 6 weight and adds 15 value).

Processing item 3 (regular):

  • For s=0: dp[0][3] becomes 4, dp[0][8] becomes 14, and dp[0][10] stays 20 (since 10+4=14 is less than 20).
  • For s=1: dp[1][9] becomes 19 (15+4 from combining the special item and small regular item).

The final maximum value is 20 (taking the two regular items), which is correct.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:55:07