E - 荷物の配送トラック / Cargo Delivery Truck Editorial by admin
GPT 5.2 HighOverview
We determine whether \(N(\le 15)\) items can be assigned to \(M(\le 15)\) trucks with weight limits, where each item must be assigned to exactly one truck. This is solved using bitmask DP (subset DP).
Analysis
Key Observations
- Since \(N,M\le 15\), a DP approach managing “which items have already been loaded” using a bitmask (\(0\sim 2^N-1\)) is practical.
- For each truck, we need to select “a set of items to load.” This becomes a problem of selecting “a subset of the remaining items.”
Why the Naive Solution is Too Slow
If we enumerate all subsets of remaining items for each truck, the number of states is \(2^N\), and subset enumeration for each state is at most \(2^{N}\), leading to approximately \(O(M\cdot 3^N)\) in the worst case (a common pattern in subset DP). Even with \(N=15\), this can become heavy depending on the implementation.
How to Solve This (Optimization Techniques)
- Early pruning of impossible cases
- If \(\max_i W_i > \max_j C_j\), that item cannot fit in any truck, so output
Noimmediately - If \(\sum_i W_i > \sum_j C_j\), total capacity is insufficient, so output
Noimmediately
- If \(\max_i W_i > \max_j C_j\), that item cannot fit in any truck, so output
- Reduce the number of trucks
- At most \(N\) trucks will actually carry items, so when \(M>N\), it suffices to keep only the \(N\) trucks with largest capacities (smaller trucks are less useful).
- Process trucks with smaller capacity first
- Trucks with smaller capacity have limited subsets that can fit, so reachable states grow slowly, keeping the DP from exploding.
- Switch enumeration methods based on the situation
- Pre-compute a list
fit_listof subsets that fit in the truck (subsets with weight sum \(\le cap\)), and use it for transitions - For a state
mask, enumerate all subsets of the “remaining setrem” - Choose whichever method processes fewer subsets.
- Pre-compute a list
Algorithm
1. Preprocessing
- Let
full = (1<<N)-1represent “all items have been loaded.” - Sort truck capacities \(C\) in descending order and keep only \(M=\min(M,N)\) trucks (prioritizing larger ones).
- Since we want to process smaller capacities first in the DP, sort the remaining \(C\) in ascending order.
- Precompute the weight sum
sum_w[mask]for each subsetmask.- Example: Take the lowest set bit
lsbofmask, thensum_w[mask] = sum_w[mask ^ lsb] + W[i]can be computed in \(O(2^N)\).
- Example: Take the lowest set bit
2. DP Definition
dp[mask] = True
“It is possible to have loaded the item setmask(items corresponding to set bits) using the trucks processed so far”- Initial state:
dp[0]=True(nothing loaded yet) - Maintain
reachableas a “list of masks currently True” to avoid unnecessary full traversals.
3. Transitions (for each truck capacity cap)
- First, for each
mask in reachable, computerem = full ^ mask(remaining items), and- If
sum_w[rem] <= cap, we can load all remaining items on this truck and finish, so outputYesimmediately.
- If
- Next, use subsets
subthat can be loaded on this truck (sum_w[sub] <= cap) for transitions.- Since “using this truck empty” is allowed, start with
new_dp = dp[:]. - The transition destination is
nm = mask | sub(with the condition thatsubdoesn’t overlap withmask).
- Since “using this truck empty” is allowed, start with
Compare two subset enumeration methods and use the faster one:
- Share fit_list across all states: check sub in fit_list and transition if (sub & mask)==0
- Enumerate subsets of rem for each state: iterate with sub = rem; sub=(sub-1)&rem and transition if sum_w[sub] <= cap
Finally, set dp = new_dp, update reachable, and after processing all trucks, output Yes if dp[full], otherwise No.
(Simple Example)
- If \(N=3\), states are mask=0..7.
- For example, mask=101(2) means “items 1 and 3 have been loaded,” with remaining rem=010.
- If the next truck has sufficient capacity, we can load all of rem and reach full=111.
Complexity
- Time complexity: Typically \(O(2^N + \sum_{j=1}^{M} (\text{reachable count}) \times \min(|\text{fit\_list}_j|, 2^{\text{remaining count}}))\)
(Roughly \(O(M\cdot 3^N)\) in the worst case, but with \(N\le 15\), reachable state management, enumeration switching, and processing smaller capacities first, it runs fast enough in practice) - Space complexity: \(O(2^N)\) (
dp,sum_w,popc, etc.)
Implementation Notes
When \(M>N\), keep only the \(N\) largest capacity trucks: Since at most \(N\) trucks will be non-empty, discarding extra small-capacity trucks doesn’t affect the answer.
Precomputing
sum_w[mask]is crucial to make subset weight checks \(O(1)\).Processing smaller capacities first keeps reachable states from growing too large, stabilizing the DP.
Switching enumeration methods (
fit_listvs subset enumeration ofrem) is the key to optimization, handling both cases when capacity is small and when few items remain.Source Code
import sys
def main():
input = sys.stdin.readline
N, M = map(int, input().split())
W = list(map(int, input().split()))
C = list(map(int, input().split()))
full = (1 << N) - 1
C.sort(reverse=True)
M = min(M, N)
C = C[:M]
if not C:
print("No")
return
if max(W) > max(C):
print("No")
return
if sum(W) > sum(C):
print("No")
return
# Process smaller capacities first to keep reachable states small
C.sort()
sum_w = [0] * (1 << N)
for mask in range(1, 1 << N):
lsb = mask & -mask
i = lsb.bit_length() - 1
sum_w[mask] = sum_w[mask ^ lsb] + W[i]
popc = [0] * (1 << N)
for mask in range(1, 1 << N):
popc[mask] = popc[mask >> 1] + (mask & 1)
dp = [False] * (1 << N)
dp[0] = True
reachable = [0]
for cap in C:
# If any current state can finish all remaining items with this truck, done
for mask in reachable:
rem = full ^ mask
if sum_w[rem] <= cap:
print("Yes")
return
fit_list = [sub for sub in range(1, 1 << N) if sum_w[sub] <= cap]
fit_len = len(fit_list)
new_dp = dp[:] # allow leaving this truck empty
new_reachable = reachable[:] # start with existing states
for mask in reachable:
if mask == full:
continue
rem = full ^ mask
# Choose faster enumeration strategy per state
if fit_len < (1 << (N - popc[mask])):
for sub in fit_list:
if (sub & mask) == 0:
nm = mask | sub
if not new_dp[nm]:
new_dp[nm] = True
new_reachable.append(nm)
else:
sub = rem
while sub:
if sum_w[sub] <= cap:
nm = mask | sub
if not new_dp[nm]:
new_dp[nm] = True
new_reachable.append(nm)
sub = (sub - 1) & rem
dp = new_dp
reachable = new_reachable
print("Yes" if dp[full] else "No")
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: