描述:
假设你去野营。有一个重量为6(limit = 6)的背包,需要决定该携带某些东西,这些东西都有自己的重量和价值,如何选择能保证携带的东西具有最大价值?
水(sublimit:3,value:10)
书(sublimit:1,value:3)
食物(sublimit:2,value:9)
夹克(sublimit:2,value:5)
相机(sublimit:1,value:6)
解题思路:
所有dp问题都可以用 n*m 的二维矩阵解决,从左上角开始,按照从左往右,从上往下的顺序,依
次填充矩阵,填满以后便可看出来答案。
每个单元格求值公式:
matrix[i][j] = max(matrix[i - 1][j], value[i] + matrix[i - 1][j - 当前物品的限制])
此公式中 i j 的值依赖其上一行内元素的值,因此永远是有解的。
方案一 :
把限制条件也纳入矩阵,这个dp方法是通用方法,但是代码复杂,对关键策略的描述不清晰,建议使用方案二
matrix = []
sublimits = 0
limits = []
values = []
def makematrix():
global limits
limits = [int(x) for x in input().strip().split()]
global sublimits
sublimits = [int(x) for x in input().strip().split()]
global values
values = [int(x) for x in input().strip().split()]
# 构建第一行
line = []
for j in range(0, len(limits) + 1):
line.append(j)
matrix.append(line)
# 构建其他行
for i in range(0, len(sublimits)):
newline = [0 for k in range(0, len(limits) + 1)]
newline[0] = sublimits[i]
matrix.append(newline)
def dp(row, col):
first = 0
second = 0
if row < 1 or col < 1:
return 0
# 矩阵位于自己上面的那个节点
if row == 1:
first = 0
else:
first = matrix[row - 1][col] # 矩阵位于自己上面的那个节点
if sublimits[row - 1] > limits[col - 1]: # 如果自身的限制大于当前列的限制,则为0
second = 0
else:
if row == 1:
second = values[row - 1] # 如果是第一行,那么上一行是不存在的,又因为已经满足了自身限制小于总限制,所以就以自己的当前价值作为本节点的值
else:
if col == 1:
second = values[row - 1] # 当前的分数 + 在上一行(ROW-1)中找总限制减去当前限制(limits[col-1]-sublimits[row-1])后的值
else:
second = values[row - 1] + matrix[row - 1][limits[col - 1] - sublimits[row - 1]] # 当前的分数 + 在上一行(ROW-1)中找总限制减去当前限制(limits[col-1]-sublimits[row-1])后的值
matrix[row][col] = max(first, second)
print(matrix[row][col])
makematrix()
# 单元格遍历顺序是 按行遍历
for row in range(1, len(sublimits) + 1):
for col in range(1, len(limits) + 1):
dp(row, col)
方案二:
matrix = []
sublimits = 0
limits = []
values = []
def makematrix():
global limits
limits = [int(x) for x in input().strip().split()]
global sublimits
sublimits = [int(x) for x in input().strip().split()]
global values
values = [int(x) for x in input().strip().split()]
# 构建矩阵
for i in range(0, len(sublimits)): #共sublimits行
newline = [0 for k in range(0, len(limits))] #每行limits列
matrix.append(newline)
# 构建第一行
for j,ele in enumerate(limits):
if ele >= sublimits[0]:
matrix[0][j] = values[0]
else:
matrix[0][j] = 0
first = 0
second = 0
# 构建第一列
for k in range(1,len(sublimits)): #第一列的第一行已经在构建第一行时构建好了
first = matrix[k-1][0]
if limits[0]>=sublimits[k]:
second = values[k]
else:
second = 0
matrix[k][0] = max(first,second)
def dp(row, col):
first = 0
second = 0
if row < 1 or col < 1:
return 0
# 矩阵位于自己上面的那个节点
first = matrix[row - 1][col] # 矩阵位于自己上面的那个节点
# 如果自身的限制大于当前列的限制,则为0
if sublimits[row - 1] > limits[col - 1]:
second = 0
# 否则为当前的分数 + 在上一行(ROW-1)中找总限制减去当前限制(limits[col-1]-sublimits[row-1])后的值
else:
# 找到 总限制减去当前限制 得到的 限制值在表中的哪一列
ind = 0
for index,ele in enumerate(limits):
if ele == limits[col] - sublimits[row]:
ind = index
second = values[row] + matrix[row - 1][ind] # 当前的分数 + 在上一行(ROW-1)中找总限制减去当前限制(limits[col-1]-sublimits[row-1])后的值
matrix[row][col] = max(first, second)
makematrix()
# 单元格遍历顺序是 按行遍历
for row in range(1, len(sublimits)):
for col in range(1, len(limits)):
dp(row, col)
print(matrix)