Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 硬币更换,动态规划,但首次使用后硬币价值降低_Algorithm_Dynamic Programming_Knapsack Problem_Coin Change - Fatal编程技术网

Algorithm 硬币更换,动态规划,但首次使用后硬币价值降低

Algorithm 硬币更换,动态规划,但首次使用后硬币价值降低,algorithm,dynamic-programming,knapsack-problem,coin-change,Algorithm,Dynamic Programming,Knapsack Problem,Coin Change,有很多关于硬币兑换的问题和答案,但我找不到这一个,我想知道这是否是一个硬币兑换的问题 基本上我有一堆不同的硬币,每个硬币的数量是无限的 比如说有很多不同的面额。每个堆栈都是无限的。(因此,25摄氏度硬币的数量是无限的,2摄氏度硬币的数量是无限的,等等) 然而,在每一堆硬币的顶部是一种特殊的硬币,其价值大于(或等于)下面的硬币。如果不在上面使用这枚硬币,我就无法访问下面的硬币 我想算出的是一笔特定金额所需的最小硬币数量 我认为这是可解的动态规划,但我不确定如何将此限制添加到传统解决方案中 我想知道

有很多关于硬币兑换的问题和答案,但我找不到这一个,我想知道这是否是一个硬币兑换的问题

基本上我有一堆不同的硬币,每个硬币的数量是无限的

比如说有很多不同的面额。每个堆栈都是无限的。(因此,25摄氏度硬币的数量是无限的,2摄氏度硬币的数量是无限的,等等)

然而,在每一堆硬币的顶部是一种特殊的硬币,其价值大于(或等于)下面的硬币。如果不在上面使用这枚硬币,我就无法访问下面的硬币

我想算出的是一笔特定金额所需的最小硬币数量

我认为这是可解的动态规划,但我不确定如何将此限制添加到传统解决方案中


我想知道,一旦我使用了特殊硬币,是否应该将其从列表中删除,并用普通硬币替换,但我似乎无法推断这是否会破坏算法。

看起来像一个经典的动态规划问题,其中的挑战是正确选择状态

通常,我们选择所选硬币的总数作为问题状态,选择所选硬币的数量作为状态值。过渡是我们能得到的一切可能的硬币。如果我们有25c和5c硬币,我们可以从有值计数的状态总和转移到状态
Sum+25,Count+1
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))
#可用硬币:(最高硬币价值,其他硬币价值)
堆栈=[(17,8)、(5,3)、(11,1)、(6,4)]
#目标金额
目标值=70
状态=dict()
状态[(0,0)]=(0,无,无)
#DP从总和0到目标总和,自下而上:
对于xrange中的值(0,目标值):
对于每一个和,考虑每一个可能的比特组合。
对于xrange(0,2**len(堆栈))中的位:
#我们能用这些位求这个和吗?
如果(值,位)处于以下状态:
计数=状态[(值,位)][0]
#让我们从每一堆硬币中取出一枚
对于X范围内的堆栈(0,len(堆栈)):
堆栈_位=(1计数+1:
#第一个元素是硬币号码
#二是“回溯参考”
#第三是这一步的硬币价值
状态[转换]=(计数+1,(值,位),成本)
最小计数=目标值+1
最小状态=无
#找到所有状态的最佳解决方案,求和=目标值
对于xrange(0,2**len(堆栈))中的位:
如果(目标_值,位)处于以下状态:
计数=状态[(目标值,位)][0]
如果计数<最小计数:
最小计数=计数
最小状态=(目标值,位)
收集的硬币=[]
状态=最小状态
如果状态==无:
打印“无解决方案”
其他:
#按照回溯参考获得单个硬币
而状态(0,0):
收集的硬币。附加(州[州][2])
州=州[州][1]
打印“解决方案:%s”%列表(已反转(收集的硬币))

看起来像一个经典的动态规划问题,其中的挑战是正确选择状态

通常,我们选择所选硬币的总数作为问题状态,选择所选硬币的数量作为状态值。我们可以选择所有可能的硬币。如果我们有25c和5c硬币,我们可以从状态总和和值计数移动到状态
sum+25,计数+1
sum+5,计数+1

对于您的限制,状态应该增加关于哪个特殊(顶部)的信息硬币被拿走了。所以你为每一堆硬币添加一个位。然后你只需要定义每个州可能的转换。很简单:如果设置了一个位为堆栈,这意味着顶级硬币已经被拿走了,你可以将一个非顶级硬币从该堆栈添加到状态总和,保持所有位不变。否则,你可以从该sta拿走顶级硬币ck,ad将其值转换为状态和,并设置相关位

从状态开始,求和为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))
#可用硬币:(最高硬币价值,其他硬币价值)
堆栈=[(17,8)、(5,3)、(11,1)、(6,4)]
#目标金额
目标值=70
状态=dict()
状态[(0,0)]=(0,无,无)
#DP从总和0到目标总和,自下而上:
对于xrange中的值(0,目标值):
对于每一个和,考虑每一个可能的比特组合。
对于xrange(0,2**len(堆栈))中的位:
#我们能用这些位求这个和吗?
如果(值,位)处于以下状态:
计数=状态[(值,位)][0]
#让我们从每一堆硬币中取出一枚
对于X范围内的堆栈(0,len(堆栈)):
堆栈_位=(1计数+1:
#第一个元素是硬币号码
#二是“回溯参考”
#第三是这一步的硬币价值
状态[转换]=(计数+1,(值,位),成本)
民宿