201871030139-于泽浩 实验二 个人项目D{0-1} KP
201871030139-于泽浩 实验二 个人项目D{0-1} KP
项目 | 内容 |
---|---|
课程班级博客连接 | 2018级卓越班 |
这个作业要求连接 | 软件工程个人项目 |
我的课程学习目标 | (1)掌握软件项目个人开发流程; (2)掌握Github发布软件项目的操作方法。 |
这个作业在哪些方面帮助我实现学习目标 | (1)详细阅读《构建之法》第1章、第2章,掌握PSP流程; (2)复习背包问题相关算法知识; (3)将项目源码的完整工程文件提交到Github账号的项目仓库中 |
项目Github的仓库链接地址 | 仓库链接地址 |
实验内容
任务1:阅读教师博客“常用源代码管理工具与开发工具”内容要求,点评班级博客中已提交相关至少3份作业。
任务2:详细阅读《构建之法》第1章、第2章,掌握PSP流程
- 软件开发流程
软件工程包括了开发,运营, 维护软件的过程中有很多技术, 做法, 习惯, 和思想。软件工程把这些相关的技术和过程统一到一个体系中, 叫 “软件开发流程”,软件开发流程的目的是为了提高软件开发, 运营, 维护的效率,以及用户满意度, 可靠性,和软件的可维护性。
- PSP的特点
PSP 的特点:
- 不局限于某一种软件技术 (如编程语言), 而是着眼于软件开发的流程, 这样不同应用的工程师可以互相比较。
- 不依赖于考试, 而主要靠工程师自己收集数据, 然后统计提高。
- 在小型,初创的团队中, 高质量的项目需求很难找到,这意味着给程序员的输入质量不高,在这种情况下, 程序员的输出 (程序/软件) 往往质量不高, 然而这并不能全部由程序员负责。
- PSP 依赖于数据
- 需要工程师输入数据, 记录工程师的各项活动, 这本身就需要不小的代价。
- 如果数据不准确或有遗失, 怎么办? 让工程师编造一些?
- 如果一些数据不利于工程师本人 (例如: 花很多时间修改缺陷), 我们怎么能保证工程师能如实地记录这些数据呢?
- PSP的目的是记录工程师如何实现需求的效率, 而不是记录顾客对产品的满意度。工程师可能很高效地开发出一个顾客不喜欢的软件, 那这个工程师还是一个优秀的工程师么?
任务3
项目开发背景:背包问题(Knapsack Problem,KP)是NP Complete问题,也是一个经典的组合优化问题,有着广泛而重要的应用背景。{0-1}背包问题({0-1 }Knapsack Problem,{0-1}KP)是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?
D{0-1} KP 是经典{ 0-1}背包问题的一个拓展形式,用以对实际商业活动中折扣销售、捆绑销售等现象进行最优化求解,达到获利最大化。D{0-1}KP数据集由一组项集组成,每个项集有3项物品可供背包装入选择,其中第三项价值是前两项之和,第三项的重量小于其他两项之和,算法求解过程中,如果选择了某个项集,则需要确定选择项集的哪个物品,每个项集的三个项中至多有一个可以被选择装入背包,D{0-1} KP问题要求计算在不超过背包载重量 的条件下,从给定的一组项集中选择满足要求装入背包的项,使得装入背包所有项的价值系数之和达到最大;D{0-1}KP instances数据集是研究D{0-1}背包问题时,用于评测和观察设计算法性能的标准数据集;动态规划算法、回溯算法是求解D{0-1}背包问题的经典算法。查阅相关资料,设计一个采用动态规划算法、回溯算法求解D{0-1}背包问题的程序,程序基本功能要求如下:
1.可正确读入实验数据文件的有效D{0-1}KP数据;
2.能够绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图;
3.能够对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序;
4.用户能够自主选择动态规划算法、回溯算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位);
5.任意一组D{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件。
1. 需求分析
- 本次题目主要是通过动态规划算法和回溯算法来求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位),而0/1背包问题对于物品的选择只有两种:装入或者不装入背包。那么如何选择装入背包的物品,使得包中物品的总价值最大?我将使用动态规划算法分以下三步来实现:
- 划分子问题:将原问题分解为若干个子问题,每个子问题对应一个决策阶段,并且子问题之间具有重叠关系。
- 确定动态规划函数:根据子问题之间的重叠关系找到子问题满足的递推关系式(即动态规划函数),这是动态规划算法的关键。
- 填写表格:设计表格,以自底向上的方式计算各个子问题的解并填表,实现动态规划过程。
2. 功能设计
(1)读取文件数据:可正确读入实验数据文件的有效D{0-1}KP数据;
(2)绘制散点图:绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图;
(3)排序:对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序;
(4)求解最优解和时间:求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位);
(5)将数据结果保存为txt文件:将一组D{0-1} KP数据的最优解、求解时间和解向量保存为txt文件;
3. 设计实现
- 本次实验设计主要针对5个功能的实现来设计的。
- 第一个模块是正确的读取数据(这是后面功能实现的前提),通过观察数据我发现了数据规律(如:weight数据满足lnum == 8 + group * 8)利用Python读取特定行的数据,也利用python的切片功能实现了n和c的获取;
- 第二个模块则是利用python的matplotlib库中scatter函数轻松实现;
- 第三个模块先是使用dict(zip(list1,list2))生成字典实现价值重量比和物品的对于关系,然后对价值重量比排序,最后利用字典的键值对的关系输出对于物品;
- 第四个模块则是利用上学期所学动态规划算法来实现,不一样的是之前所学为C++程序,本次实验是根据之前内容改写成python程序实现;
- 第五个模块则穿插在第四个模块中间将对于数据写入文件当中。
4. 测试运行
- 读取文件数据:
- 错误结果(考虑片面)
- 正确测试
- 绘制散点图
- 测试结果
- 测试结果
- 排序
- 测试结果
- 测试结果
- 求解最优解和时间
- 测试结果
- 测试结果
- 将数据结果保存为txt文件
- 测试结果
- 测试结果
5. 代码展示
for line in f: #按行读取
lnum += 1
if(lnum == 4 + group * 8):
#获取物品数量n
s = line.strip().split(' ')
n = str(s[3])
n = n.strip().split('d=3*')
n = str(n[1])
n = n.strip().split(',')
n = 3* int(n[0])
print("物品数量 n = :",n)
#获取背包容量c
c = str(s[-1])
c = c.strip().split('.')
c = int(c[0])
print("背包容量 c = :",c)
#获取各个物品价值存入V中
if(lnum == 6 + group * 8):
V = line.strip().split(',')
#print("物品价值 V = :",V)
#获取各个物品重量存入W中
if(lnum == 8 + group * 8):
W = line.strip().split(',')
#print("物品重量 W = ",W)
- 展示原因:为什么展示这个代码?而不是展示算法、散点图等等复杂的代码?原因很简单,对于我们来说动态规划算法、回溯法和散点图绘制等等原理基本是一样的,大家理解了就可以实现,而我们每个人的区别就在于如何读取数据并处理数据,这段代码虽然简单,但却包含了我是如何处理数据的,不过也存在了一些问题(由于数据第0组和第1组结尾与其他组的结尾不同造成,前者是“,”后者是“.”),但经过下面代码改进解决了问题。
#获取各个物品价值存入V中
if(lnum == 6 + group * 8):
V = line.strip().split(',')
Vv = V[-1].split('.')
V[-1] = Vv[0]
#print("物品价值 V = :",V)
#获取各个物品重量存入W中
if(lnum == 8 + group * 8):
W = line.strip().split(',')
Ww = W[-1].split('.')
W[-1] = Ww[0]
6. 总结
- 本次实验我的“模块化”实际上还是一个大程序,一是因为使用Python相比其他语言来说代码少,对于完成本次实验的调试影响不大;二是在实验前我花了大量的时间去分析设计实验,以经对于实验内容了然于心(所谓磨刀不误砍柴工);三是由于没有很好的利用好PSP,时间安排出现紧张而最后的时间里仍然坚持自己完成,为节约时间便没有设计独立模块,而是根据自己分析的结果使用大程序里的“模块化”来完成实验,这是我未来要改正的错误,值得总结出来并反思。
7.展示完整PSP
任务内容 | 计划共完成需要的时间(h) | 实际完成需要的时间(h) |
---|---|---|
计划 | 1 | 0.8 |
· 估计这个任务需要多少时间,并规划大致工作步骤 | 1 | 0.8 |
开发 | 26.5 | 27 |
· 需求分析 (包括学习新技术) | 3 | 2 |
· 生成设计文档 | 2 | 2 |
· 设计复审 (和同事审核设计文档) | 0.5 | 0.5 |
· 代码规范 (为目前的开发制定合适的规范) | 1 | 0.5 |
· 具体设计 | 3 | 2 |
· 具体编码 | 12 | 15 |
· 代码复审 | 3 | 2 |
· 测试(自我测试,修改代码,提交修改) | 2 | 3 |
报告 | 3 | 5 |
· 测试报告 | 2 | 3 |
· 计算工作量 | 0.5 | 1 |
· 事后总结 ,并提出过程改进计划 | 0.5 | 1 |
- 注:本次设计的PSP各个阶段是以小时为单位来估计的,误差存在是一个要点,而更重要的一个感悟是本次设计没有考虑这些阶段具体在那天完成,导致开始的一个星期并没有很认真去完成,而是拖到后面才去实现的。所有我个人认为在以后的设计中我们有必要对PSP各个阶段的具体完成时间(那天的什么时间)也写进去。
- PSP反思:通过实际与计划的对比我发现自己编码能力还有待欠缺,导致自己在具体编码过程中不仅慢,也出现了一写问题以至于还影响了自己测试的计划实际,因为自己要因为编码错误而不断修改测试,在这些方面使得我浪费了很多时间。结合整个作业过程,这个问题也有自己编码不规范没有“模块化”的习惯,使得所有功能在一个大程序里完成的因素。
任务4:完成任务3的程序开发,将项目源码的完整工程文件提交到你注册Github账号的项目仓库中。
注:由于不太熟悉一些命令,前后修改后直接替换原有文件。
感 悟
- “真不容易!又熬了个通宵现在是5:50,真的有必要写一下感悟!”这是此时此刻我最大的感悟!还记得两个星期前刚看到作业内容的时候,心想天哪这比我之前的期末大作业还要难,完了完了这回要0分了。于是接连一个星期都没有去再看一眼作业,直到那天录课,我才意识到原来班里同学们都在做而且好多已经要做完了。课后想了想不行啊,自己还不想放弃也不想去抄袭其他同学的,怎么办?于是我认真的去读了PSP,发现构建之法这本书读起来很有意思,内容讲解并不是我原先想的那么古板无聊。真的来了兴趣之后的我开始认真分析任务3的各个要求,发现自己最大的困难只是读数据因为后面的任务自己在其他实验课上都已经完成过,变来了信心。通过反复尝试和思考终于发现了文件数据的规律(前文已经提过),于是利用python顺利的完成了数据的正确提取。不过值得回忆的就是博客里提出的那个错误测试截图,是由于自己的失误对文本内容的片面考虑而产生不过好在自己去测试了不同的组的数据,才避免了后续的错误。最后,虽然感觉很辛苦不容易,但自己认真完成的过程很爽!