数据结构与算法课程设计

一、题目

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),所以要根据不同的数据情况选择合适的算法。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一些关于数据结构、内部算法与排序课程设计的建议。 首先,您需要确定该课程设计的目标和学习内容。您可以考虑以下几个方面: 1. 数据结构的基本原理和常用数据结构,如线性表、栈、队列、树、图等。 2. 内部算法的基本概念和分类,如贪心算法、分治算法、动态规划算法等。 3. 排序算法的基本原理和分类,如冒泡排序、选择排序、插入排序、快速排序、归并排序等。 4. 采用的编程语言和开发工具,如C++或Java编程语言,Visual Studio或Eclipse开发工具等。 5. 可能遇到的问题和解决方案,如算法复杂度分析、算法实现错误、排序算法优化等。 接下来,您可以根据以上考虑的内容,制定课程设计的详细计划。以下是一个可能的课程设计计划: 1. 第一周:介绍数据结构的基本原理和常用数据结构,讲解线性表、栈、队列、树、图等数据结构的实现和应用。 2. 第二周:学习内部算法的基本概念和分类,讲解贪心算法、分治算法、动态规划算法算法的实现和应用。 3. 第三周:介绍排序算法的基本原理和分类,讲解冒泡排序、选择排序、插入排序、快速排序、归并排序等排序算法的实现和应用。 4. 第四周:实现一个基于数据结构和内部算法的实际应用,如一个简单的迷宫求解器或文本编辑器。 5. 第五周:总结和回顾整个课程设计的过程,讨论可能的改进和优化方案。 希望这些建议能够对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值