算法思路
利用动态规划算法,寻找每个状态下背包内物品的最优解,最终得出最终最优解。
Readme
运行说明:
7个.dat后缀文件保存了7组地址数据储存于data文件夹中,将.py和.exe文件放在data的父级文件夹中。直接运行01Packet.exe,将显示每组数据的原始数值,和背包价值最优解以及放入背包的物品序号。程序窗口将保持300秒。
数据结构:
整型product_count:物品数量
整型capacity:背包容量
列表weight_array:物品重量
列表value_array:物品价值
算法设计:
1、首先从配置文件中获取物品数量、背包容量、物品重量和物品价值,分别存入上述对应的数据结构中。
2、定义一个二维列表value,其行数为物品数量+1,其列数为背包容量+1,初始化二维列表中所有值为0。
3、value[i][j]代表当前背包剩余容量j的条件下,前i个物品的最优解。
4、在每一种容量条件下遍历每一件物品,将现有状态value与前一状态value对比,即当背包可以装下物品i,且装下比不装下的value值更大,则装入。
5、递归完成二维列表value的每一值设定,二维列表内最大值即为最优解(价值最大)。
6、从最优解处回溯,当二维列表第i行大于第i-1行同一位置的值时,则代表放入第i个物品,并减去对应重量。
7、回溯至value[0][0],可得出放入的所有物品。
代码
# -*- coding: utf-8 -*-
import time
import glob
# 定义01背包问题的类
class Packet:
#初始化参数物品数量,背包容量,重量,价值
def __init__(self,product_count,capacity,weight_array,value_array):
self.product_count = product_count
self.capacity = capacity
self.weight_array = weight_array
self.value_array = value_array
# data函数用于打印每组数据
def data(self):
print('物品个数:', self.product_count)
print('背包容量:', self.capacity)
print('商品重量:', self.weight_array)
print('商品价值:', self.value_array)
# 动态规划算法
def Dynamic_Planning(self):
#value[i][j]:当前背包容量 j,前 i 个物品最佳组合对应的价值,初始化置0,
value = [[0 for j in range(self.capacity + 1)] for i in range(self.product_count + 1)]
# 利用循环使每一个物品遍历背包容量
for i in range(1, self.product_count + 1):
for j in range(1, self.capacity + 1):
value[i][j] = value[i - 1][j] # 将背包置于放入上一个物品的状态(前一状态)
# 当背包剩余容量大于等于当前物品,且前一状态价值(由于上一条语句,此时前一状态为value[i][j])小于现状态价值时,置换
if j >= int(self.weight_array[i - 1]) and value[i][j] < value[i - 1][j - int(self.weight_array[i - 1])] + int(
self.value_array[i - 1]):
value[i][j] = value[i - 1][j - int(self.weight_array[i - 1])] + int(self.value_array[i - 1])
return value
# 打印最优解
def show(self):
# 从最优解处遍历物品,当value大于上一行同样位置的value时,表示放进该物品
value = self.Dynamic_Planning()
print('最大价值为:', value[self.product_count][self.capacity])
x = [False for i in range(self.product_count)]
j = self.capacity
for i in range(self.product_count, 0, -1):
if value[i][j] > value[i - 1][j]: #此行大于上一行同位置的值
x[i - 1] = True # 放入该物品
j -= int(self.weight_array[i - 1]) # 减少对应背包容量
print('背包中所装物品为:')
for i in range(self.product_count):
if x[i]:
print('第' + str(i + 1) + '个 ', end=' ')
def main():
file = glob.glob('./data/*.dat') # 获取指定目录下所用.dat后缀文件
for i,filename in enumerate(file): # 循环获取序号与文件名
# filename = "input_assign01_0"+str(i+1)+".dat"
print('\n\n第%d组数据'%(i+1))
# 打开文件,逐行读取数据
with open(filename, 'r') as f:
product_count = f.readline()
capacity = f.readline()
weight_array = f.readline()
value_array = f.readline()
# 将重量与价值转化为列表形式
weight_array = weight_array.strip().split(" ")
value_array = value_array.strip().split(" ")
product_count = int(product_count)
capacity = int(capacity)
Packet(product_count, capacity, weight_array, value_array).data() # 调用类方法data
Packet(product_count, capacity, weight_array, value_array).show() # 调用类方法show
print('\nFinish!')
time.sleep(300)
if __name__ == '__main__':
main()