課題は状態を正しく選択することである古典的な動的計画問題のように見えます。
通常、選択したコインの合計を問題の状態として選択し、選択したコインの数を状態値として選択します。トランジションは、私たちが取ることができるすべてのコインです。25c と 5c のコインがある場合、値が Count の状態 Sum から状態Sum+25,count+1
andに移動できSum+5,count+1
ます。
あなたの制限のために、どの特別な(トップ)コインが取られたかについての情報で状態を増強する必要があります。したがって、コインのスタックごとにビットを追加します。次に、すべての状態から可能な遷移を定義する必要があります。それは簡単です: スタックのビットが設定されている場合、それはトップ コインが既に取得されていることを意味し、すべてのビットを同じに保ちながら、そのスタックから状態合計に非トップ コインを追加できます。それ以外の場合は、そのスタックから一番上のコインを取り、その値を州の合計に追加し、関連するビットを設定できます。
合計が 0、すべてのビットがクリア、値が 0 の状態から開始し、最小の合計からターゲットまでの状態を構築します。
最後に、ビットとのすべての可能な組み合わせを反復処理する必要があります。状態の値をターゲットの合計とそのビットの組み合わせと比較します。最小値を選択してください - それが答えです。
ソリューション コードの例:
#Available coins: (top coin value, other coins value)
stacks = [(17,8),(5,3),(11,1),(6,4)]
#Target sum
target_value = 70
states = dict()
states[(0,0)] = (0,None,None)
#DP going from sum 0 to target sum, bottom up:
for value in xrange(0, target_value):
#For each sum, consider every possible combination of bits
for bits in xrange(0, 2 ** len(stacks)):
#Can we get to this sum with this bits?
if (value,bits) in states:
count = states[(value,bits)][0]
#Let's take coin from each stack
for stack in xrange(0, len(stacks)):
stack_bit = (1 << stack)
if bits & stack_bit:
#Top coin already used, take second
cost = stacks[stack][1]
transition = (value + cost, bits)
else:
#Top coin not yet used
cost = stacks[stack][0]
transition = (value + cost, bits | stack_bit)
#If we can get a better solution for state with sum and bits
#update it
if (not (transition in states)) or states[transition][0] > count + 1:
#First element is coins number
#Second is 'backtrack reference'
#Third is coin value for this step
states[transition] = (count+1, (value,bits), cost)
min_count = target_value + 1
min_state = None
#Find the best solution over all states with sum=target_value
for bits in xrange(0, 2 ** len(stacks)):
if (target_value,bits) in states:
count = states[(target_value,bits)][0]
if count < min_count:
min_count = count
min_state = (target_value, bits)
collected_coins = []
state = min_state
if state == None:
print "No solution"
else:
#Follow backtrack references to get individual coins
while state <> (0,0):
collected_coins.append(states[state][2])
state = states[state][1]
print "Solution: %s" % list(reversed(collected_coins))