数据结构与算法课程设计
Posted @阿证1024
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法课程设计相关的知识,希望对你有一定的参考价值。
一、题目
0-1背包问题:给定n个重量为w1,w2,w3,…,wn,价值为v1 ,v2 ,v3,…,vn的物品和容量为C的背包,求这个物品中一个最有价值的子集,使得在满足背包的容量的前提下,包内的总价值最大0-1背包问题指的是每个物品只能使用一次。
二、目的
课程设计的目的是训练学生灵活应用所学数据结构知识,独立完成问题分析、总体设计、详细设计和编程实现等软件开发全过程的综合实践能力。巩固、深化学生的理论知识,提高编程水平,并在此过程中培养他们严谨的科学态度和良好的工作作风。课程设计要求独立完成一个较为完整的应用需求分析,在完成设计和编程大型作业的同时,达到如下效果:
(1)深化对算法与数据结构课程中基本概念、理论和方法的理解;
(2)训练综合运用所学知识处理实际问题的能力;
(3)使程序设计与调试水平有一个明显的提高;
(4)培养科学算法设计与分析能力,提高创造性思维能力。
三、内容
(1) 分析问题,进行问题建模,根据模型选择合适的数据结构。
(2) 物品编号、重量、价值信息来源于文件。
(3) 根据选定的数据结构选择算法设计策略,设计两种以上算法。
(4) 根据算法设计策略设计算法。
(5) 分析算法的时间复杂度和空间复杂度,并比较算法优劣。
(6) 讨论算法改进、优化方法。
四、需求分析
(1)问题描述:给定各个物品的价值和重量以及背包的容量,求出最优的装载方法使得背包所装物品的总价值最大。
(2)功能要求:根据已有数据通过程序求出最优子集。
(3)数据要求:从文件中读取数据,第一行数据代表物品数量和背包容量,接下来的每一行分别代表物品的价值和物品的重量。
(4)测试数据:
3 4
1500 1
3000 2
2000 3
五、逻辑结构设计
1. 算法一:枚举法
(1)数据结构:树结构。
(2)模块划分:main()主流程逻辑函数,get_res()得出最终结果。
(3)初始化path(用来表示物品的存放情况)和cpath(用来表示当前物品存放的情况),调用get_res()方法获取最优放入情况对应的价值,打印最终结果。
2. 算法二:动态规划
(1)数据结构:无。
(2)模块划分:main()主流程逻辑函数,get_res()得出最终结果。
(3)初始化v(用来记录每种分情况下的最优解,v是一个矩阵)和path(用来记录当前是否放入了商品,path是一个矩阵),调用get_res()方法获取最优放入情况对应的价值,打印最终结果。
六、详细设计
1. 算法一:枚举法
(1)算法思想:在搜索解空间树时,深度优先遍历,搜索每一个结点,无论是否可能产生最优解,都遍历至叶子结点,记录每次得到的装入总价值,然后记录遍历过的最大价值。
(2)函数和过程的调用关系图:
2.算法二:动态规划
(1)算法思想
(2)函数和过程的调用关系图:
七、编码与调试
a.txt内容:
3 4
1500 1
3000 2
2000 3
算法一:枚举法
# 暴力匹配-背包问题实现
# val列表记录商品的价值
val = list()
# w列表记录商品的重量
w = list()
# m代表背包的容量
m = 0
# max_value代表求得的最优解
max_value = 0
# cw, cv分别代表当前的重量和价值
cw, cv = 0, 0
# 用来表示物品的存放情况, 0代表没有放入, 1代表放入了
path = list()
# 用来表示当前物品存放的情况
cpath = list()
# 从文件中取数据
with open("E:\\java\\data\\\\a.txt", encoding='utf-8', mode='r') as f:
data = f.readlines()
res_data = list()
# 对数据进行处理
for i in data:
line_str_list = i.split(' ')
line_str_list[1] = line_str_list[1].replace('\\n','')
res_data.append(line_str_list)
for loc, i in enumerate(res_data):
if loc == 0:
m = int(i[1])
else:
val.append(int(i[0]))
w.append(int(i[1]))
"""
函数功能:
用来求得最大总价值和商品装入情况
参数i:
i表示选择的是第几个商品
返回值:
返回最大的总价值
"""
def get_res(i):
global cw, max_value, cv
if i > (len(val) - 1):
if max_value < cv and cw <= m:
# 记录最优路径
for i in range(len(path)):
path[i] = cpath[i]
max_value = cv # 更新最优解
return max_value
# 当前物品装入背包
cw += w[i]
cv += val[i]
cpath[i] = 1
get_res(i + 1) # 开始选择下一个物品
# 当前物品没有装入背包
cw -= w[i]
cv -= val[i]
cpath[i] = 0
get_res(i + 1) # 开始选择下一个物品
return max_value
def main():
# 初始化path和cpath
for i in range(len(val)):
path.append(0)
cpath.append(0)
# 调用求值函数
max_value = get_res(0) # 从0开始选择
# 打印结果值
for i in range(len(path)):
if path[i] == 1:
print("第{}件商品放入背包".format(i + 1))
print('最大价值为{}'.format(max_value))
if __name__ == '__main__':
main()
算法一调试:
算法二:动态规划
动态规划-背包问题算法实现
"""
函数功能:
计算各种子情况下的最优解
参数v:
v是各种情况最优解的矩阵
参数w:
w是各个商品的重量的列表
参数val:
val是各个商品的价值的列表
参数path:
path是当前情况是否有商品放入
返回值:
v 求得各种请款最优解的矩阵, path商品放入情况矩阵
"""
def get_res(v, w, val, path):
# 根据推出的动态规划的公式处理
"""
1. 当商品个数为0时,无论背包容量多大,最大价值肯定是0
2. 当背包容量为0时,无论商品有多少个,最大价值肯定是0
"""
for i in range(1, len(v)): # 不处理第一行
for j in range(1, len(v[0])): # 不处理第一列
if w[i - 1] > j: # 如果当前商品的重量大于背包的重量
v[i][j] = v[i - 1][j] # 那这时的最优解就是它前面所有商品求得最优解
else:
"""
如果此时背包容量能放入当前商品:
1. 放入当前商品后剩余容量还能放入其它商品
2. 只能放入当前商品
"""
# 如果放入当前商品后产生的最优解大于放入它前面所有商品的最优解
if v[i - 1][j] < (val[i - 1] + v[i - 1][j - w[i - 1]]):
# 那此时就把当前商品放入
v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]]
# 放入了新商品, 当前情况对应的值为1
path[i][j] = 1
else:
# 反之此时的最优解就是放入它前面所有商品的最优解
v[i][j] = v[i - 1][j]
return v, path
# 主逻辑函数
def main():
# val列表记录的是每个物品对应的价值
val = list()
# w列表记录的是每个物品的重量
w = list()
# v用来记录每种分情况下的最优解,v是一个矩阵
v = list()
# path用来记录当前是否放入了商品,path是一个矩阵
path = list()
# 从文件中取数据
with open("E:\\java\\data\\\\a.txt", encoding='utf-8', mode='r') as f:
data = f.readlines()
res_data = list()
# 对数据进行处理
for i in data:
line_str_list = i.split(' ')
line_str_list[1] = line_str_list[1].replace('\\n','')
res_data.append(line_str_list)
for loc, i in enumerate(res_data):
if loc == 0:
goods_num = int(i[0])
m = int(i[1])
else:
val.append(int(i[0]))
w.append(int(i[1]))
"""
# m代表背包的容量
m = int(input('请输入背包的容量:'))
# goods_num 代表商品的个数
goods_num = int(input('请输入商品的个数:'))
# 获取每个商品的价值以及它的重量
for i in range(goods_num):
value = int(input('请输入第' + str(i + 1) + '个商品的价值:'))
weight = int(input('请输入第' + str(i + 1) + '个商品的重量:'))
val.append(value)
w.append(weight)
"""
# 初始化v, 各种情况最优解默认为0
for j in range(goods_num + 1):
v.append(list())
for i in range(m + 1):
v[j].append(0)
# 初始化path, 如果当前情况放入了商品就把当前情况对应的值置为1, 反之为0
for j in range(goods_num + 1):
path.append(list())
for i in range(m + 1):
path[j].append(0)
# 调用求最优解函数
v, path = get_res(v, w, val, path)
# 输出结果
i = len(path) - 1 # 列的最大下标
j = len(path[0]) - 1 # 行的最大下标
while i > 0 and j > 0:
if path[i][j] == 1: # 从path的最后查找
print('放入第{}个商品'.format(i))
j = j - w[i - 1]
i -= 1
print('能获得的最大价值为{}'.format(v[goods_num][m]))
if __name__ == '__main__':
main()
算法二调试:
八、测试与结果分析
1.时间复杂度对比:
(1)枚举法:好情况下为 O(2^n), 最坏情况下为 O(n*2^n)
(2)动态规划:O(min{nc,2^n})
2. 结果分析:
两种算法都能算出相同的结果,但是动态规划算法要明显比枚举法效率高的多,可是在空间复杂度上枚举法为O(n),动态规划为O(nc),所以要根据不同的数据情况选择合适的算法。
以上是关于数据结构与算法课程设计的主要内容,如果未能解决你的问题,请参考以下文章