ScubaDiv编程输出逻辑错误排查:基于dynamic programming的潜水员气瓶选择问题
Hey there! Let's work through that logic error in your ScubaDiv program. This is a classic 2-dimensional knapsack problem (we're tracking two resources: oxygen and nitrogen), so I know exactly where folks usually trip up. Let's start by recapping the problem clearly, then dive into the fixes.
Quick Problem Recap
We need to pick a set of cylinders such that:
- The total oxygen meets or exceeds the diver's requirement
- The total nitrogen meets or exceeds the diver's requirement
- The total weight of the cylinders is as small as possible (since lighter gear lets the diver stay underwater longer)
Your input format looks like this (example):
1 // Number of divers
5 60 // Required oxygen = 5, required nitrogen = 60
5 // Number of available cylinders
3 36 120 // Cylinder 1: 3O2, 36N2, 120 weight
10 25 129 // Cylinder 2: 10O2,25N2,129 weight
... (and so on for each cylinder)
Common Logic Errors & How to Fix Them
1. Wrong DP Array Initialization
This is the #1 mistake I see. If you initialized your DP array to 0, that's backwards—we're looking for the minimum weight, so all states except the base case should start with a huge value (like infinity) to represent "this oxygen/nitrogen combination isn't reachable yet".
Correct Initialization (Python example):
required_ox = 5 required_ni = 60 # dp[o][n] = minimum total weight to get o units of O2 and n units of N2 INF = float('inf') dp = [[INF] * (required_ni + 1) for _ in range(required_ox + 1)] dp[0][0] = 0 # Base case: 0 O2, 0 N2 needs 0 weight
2. Broken State Transition Logic
Another common issue is not accounting for oxygen/nitrogen exceeding the requirement (which is totally fine—we just need to meet or beat the requirement) or using the wrong traversal order (leading to reusing the same cylinder multiple times).
For a 0-1 knapsack (each cylinder can be used once), we need to traverse the DP array in reverse order (from the required amount down to 0). This prevents us from reusing the same cylinder multiple times in one iteration.
Correct Transition Code:
for cyl_o, cyl_n, cyl_weight in cylinders: # Iterate backwards to avoid reusing the same cylinder multiple times for o in range(required_ox, -1, -1): for n in range(required_ni, -1, -1): if dp[o][n] != INF: # Calculate new O2/N2 levels—cap them at the required amount (no need to track excess) new_o = min(o + cyl_o, required_ox) new_n = min(n + cyl_n, required_ni) # Update the DP state if this combination is lighter if dp[new_o][new_n] > dp[o][n] + cyl_weight: dp[new_o][new_n] = dp[o][n] + cyl_weight
Capping the values at the required amount saves us from unnecessary computation—once we've met or exceeded the requirement, any extra doesn't help us.
3. Extracting the Wrong Result
If you're grabbing a value other than dp[required_ox][required_ni], that's a problem. Because we capped all excess O2/N2 to the required values, this state holds the minimum weight for meeting (or exceeding) both requirements.
4. Forgetting Multiple Divers
If your input has multiple divers, make sure to reset the DP array for each one—don't carry over state from the previous diver's calculation.
Full Working Example Code
Here's a complete, tested solution that fixes all these issues:
def solve_scuba_diving(): import sys input_data = sys.stdin.read().split() ptr = 0 num_divers = int(input_data[ptr]) ptr += 1 for _ in range(num_divers): ox_need = int(input_data[ptr]) ni_need = int(input_data[ptr+1]) ptr += 2 num_cylinders = int(input_data[ptr]) ptr += 1 cylinders = [] for __ in range(num_cylinders): o = int(input_data[ptr]) n = int(input_data[ptr+1]) w = int(input_data[ptr+2]) cylinders.append((o, n, w)) ptr += 3 # Initialize DP table INF = float('inf') dp = [[INF] * (ni_need + 1) for _ in range(ox_need + 1)] dp[0][0] = 0 # Process each cylinder for cyl_o, cyl_n, cyl_w in cylinders: for o in range(ox_need, -1, -1): for n in range(ni_need, -1, -1): if dp[o][n] != INF: new_o = min(o + cyl_o, ox_need) new_n = min(n + cyl_n, ni_need) if dp[new_o][new_n] > dp[o][n] + cyl_w: dp[new_o][new_n] = dp[o][n] + cyl_w # Output the minimum weight for this diver print(dp[ox_need][ni_need]) if __name__ == "__main__": solve_scuba_diving()
Testing this with the example input I mentioned earlier gives 249—the minimum weight from combining the 1O2/45N2 (130 weight) and 4O2/20N2 (119 weight) cylinders, which exactly meets the oxygen requirement and exceeds nitrogen.
Key Takeaways to Avoid Future Errors
- Always initialize your DP array to a large value (infinity) except the base case (0 resources = 0 weight).
- Use reverse traversal for 0-1 knapsack problems to prevent reusing items multiple times.
- Cap resource values at the required amount to keep your DP table efficient and avoid unnecessary state tracking.
- Reset your DP state for each diver if handling multiple cases.
内容的提问来源于stack exchange,提问作者Dan

