# 再学动态规划之 完全背包

## 暴力搜索

import sys
class Solution(object):

def get_small_number(self, coins, index, amount):
if amount == 0:
return 0
if amount < 0:
return -1
if index == len(coins)-1:
if amount%coins[index] != 0:
return -1
else:
return amount/coins[index]
min_res = sys.maxint
for i in range(amount/coins[index] + 1):
back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
this_amount = back_amount + i
if back_amount == -1:
this_amount = sys.maxint
min_res = min(min_res, this_amount)
return min_res

def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)


## 记忆化搜索

import sys
res = dict()
class Solution(object):

def get_small_number(self, coins, index, amount):
if amount == 0:
return 0
if amount < 0:
return -1
if index == len(coins)-1:
if amount%coins[index] != 0:
return -1
else:
return amount/coins[index]
if str(index)+'_'+str(amount) in res:
return res[str(index)+'_'+str(amount)]
min_res = sys.maxint
for i in range(amount/coins[index] + 1):
back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
this_amount = back_amount + i
if back_amount == -1:
this_amount = sys.maxint
min_res = min(min_res, this_amount)
res[str(index)+'_'+str(amount)] = min_res
return min_res

def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
res.clear()
return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)


## 动态规划

$dp[i][j]=min_{t\in[0,1+j/coins]}\{t+dp[i-1][j-coins[i]*t]\}$

import sys
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
for ix in range(len(coins)+1):
arr[ix][0] = 0
for i in range(1, len(coins)+1):
for j in range(1, amount+1):
res_min = arr[i-1][j]
for t in range(1, j/coins[i-1]+1):
res_min = min(res_min, t+arr[i-1][j-coins[i-1]*t])
arr[i][j] = res_min

return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]


$dp[i][j] = min\{dp[i-1][j],1+dp[i-1][j-x],2+dp[i-1][j-2x]+...\}$
$dp[i][j-x] =min\{dp[i-1][j-x],1+dp[i-1][j-2x],2+dp[i-1][j-3x]+...\}$

$dp[i][j] = min\{dp[i-1][j],1+dp[i][j-x]\}$

import sys
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
for ix in range(len(coins)+1):
arr[ix][0] = 0
# arr[:][0] = 1
for i in range(1, len(coins)+1):
for j in range(1, amount+1):
res_min = arr[i-1][j]
if j - coins[i-1] >= 0:
res_min = min(res_min, 1+arr[i][j-coins[i-1]])
arr[i][j] = res_min
return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]