201971010247-谢宇涵 实验二 个人项目—《{0-1}背包问题》项目报告
项目 | 内容 |
课程班级博客链接 | 查看班级博客 |
作业要求链接 | 查看作业要求 |
我的课程学习目标 | (1)掌握软件项目个人开发流程。 (2)掌握Github发布软件项目的操作方法 |
这个作业在哪些方面帮助我实现学习目标 | (1)能用贪心算法、回溯法以及动态规划法求解{0-1}背包问题 (2)学会软件设计的模块化实现 (3)理解PSP的具体流程以及特点 (4)学会代码的规范编程 |
项目Github的仓库链接地址 | 查看仓库链接 |
一、作业点评
点评作业题目 | 点评内容 |
201971010242-王凯英 实验一 软件工程准备—博客园与github的基本操作 | 详细内容请点击查看 |
201971010253-张萌 实验一 软件工程准备—课程基础 | 详细内容请点击查看 |
201971010216-李斌 实验一 软件工程准备一 阅读《构建之法现代软件工程》有感 | 详细内容请点击查看 |
二、总结详细阅读《构建之法》第1章、第2章,掌握PSP流程
(一)第一章总结
1. 软件=程序+软件工程。
2. 软件开发阶段:玩具阶段➩业余爱好阶段➩探索阶段➩成熟的产业阶段。
3. 软件的特性:①复杂性②不可见性③易变性④服从性⑤非连续性。
(二)第二章总结
1.好的单元测试的标准:
1)单元测试应该在最基本的功能/参数上验证程序的正确性
2)单元测试必须由最熟悉代码的人来写
3)单元测试过后,机器状态保持不变
4)单元测试要快
5)单元测试应该产生可重复、一致的结果
6)独立性——单元测试的运行/通过/失败不依赖于别的测试,可以认为构造数据,以保持单元测试的独立性
7)单元测试应该覆盖所有的路径
(三)PSP
PSP即个人开发流程,具体流程如下所示:
PSP流程 | 详细内容 |
计划 | 明确需求和其他相关因素,估计每个阶段的时间成本 |
开发 | (1)需求分析 (2)生成设计文档 (3)设计复审(和同事审核设计文档) (4)代码规范(为目前的开发制定合适的规范) (5)具体设计 (6)具体编码 (7)代码复审 (8)测试(自测、修改代码、提交修改) |
报告 | (1)测试报告 (2)计算工作量 (3)事后总结,并提出过程改进计划 |
PSP的特点如下:
1. 不局限于某一种软件技术。
2. 不依赖于考试。
3. 在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输入质量不高。
4. PSP依赖于数据。
5. PSP的目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度。
三、项目开发背景
背包问题(Knapsack Problem,KP)是NP Complete问题,也是一个经典的组合优化问题,有着广泛而重要的应用背景。{0-1}背包问题({0-1 }Knapsack Problem,{0-1}KP)是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?
{0-1}KP数据集是研究{0-1}背包问题时,用于评测和观察设计算法性能的标准数据集;动态规划算法、回溯算法是求解{0-1}背包问题的经典算法。查阅相关资料,设计一个采用贪心算法、动态规划算法、回溯算法求解{0-1}背包问题的程序,程序基本功能要求如下:
1.可正确读入实验数据文件的有效{0-1}KP数据;
2.能够绘制任意一组{0-1}KP数据以价值重量为横轴、价值为纵轴的数据散点图;
3.能够对一组{0-1}KP数据按重量比进行非递增排序;
4.用户能够自主选择贪心算法、动态规划算法、回溯算法求解指定{0-1} KP数据的最优解和求解时间(以秒为单位);
5.任意一组{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件。
四、项目实施过程
1.需求分析(5分)
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}背包问题的经典算法。
2.功能设计
(1)基本功能
- 采用贪心法、动态规划算法以及回溯算法求解D{0-1}背包问题
- 能读入实验数据文件并绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图
- 能够对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序
- 用户能够选择其中一种算法进行求解
- 可以将运行结果保存为txt文件
(2)拓展功能
- 能读入实验数据文件并绘制任意一组以价值/重量为纵轴的折线图
3.设计实现
(1)程序流程图如下所示:
(2)主要函数及其功能:
- get_Data函数:读入实验数据文件
- show函数:绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图
- show_zx函数:绘制任意一组以价值/重量为纵轴的折线图
- sort函数:对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序
- DFS函数:采用回溯算法求解D{0-1}背包问题
- DP函数:采用动态规划算法求解D{0-1}背包问题
- tanXin函数:采用贪心法求解D{0-1}背包问题
- path函数:控制台打印数据
- SavaTex函数:将运行结果保存为txt文件
4.测试运行,你的项目必须是可运行的,请展示项目代码的运行截图,包括题目要求实现功能对应的运行截图。这些截图说明你确实完成了项目需求,如果实现了扩展需求,也请大方秀出来。(5分)
(1)绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图,执行效果如下所示:
(2)对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序,排序结果如下所示:
(3)采用贪心求解{0-1}背包问题,并保存在checkresult.txt中,执行效果如下所示:
(4)采用回溯法求解{0-1}背包问题,并保存在checkresult.txt中,执行效果如下所示:
(5)采用动态规划法求解{0-1}背包问题,并保存在checkresult.txt中,执行效果如下所示:
(6)拓展部分,绘制任意一组以价值/重量为纵轴的折线图,执行效果如下所示:
5.代码展示
- show_zx函数:绘制任意一组以价值/重量为纵轴的折线图
def show_zx():
number = [1, 2, 3, 4, 5, 6]
rate=[0.05,1.194,1,3,0.92,0.909]
#绘制图形
# 参数linewidth设置plot()绘制的线条的粗细
plt.plot(number,rate, linewidth=5)
#语法:plot(x轴坐标,y轴坐标,其他参数设置)
# 设置图表标题,设置字体大小
#函数title()给图表指定标题,参数fontsize指定了图表中文字的大小。
plt.title("value/weight", fontsize=24)
#给x轴添加标签,设置字体大小
plt.xlabel("Number", fontsize=14)
# 给y轴添加标签,设置字体大小
plt.ylabel("value/weight", fontsize=14)
# 设置每个坐标轴的取值范围
plt.axis([0, 10, 0, 3]) #[x.x,x.y,y.x,y.y]
# tick_params()设置刻度标记的大小,设置刻度的样式
plt.tick_params(axis='both', labelsize=14)
# 打开matplotlib查看器,并显示绘制的图形
plt.show()
- DFS函数:采用回溯算法求解D{0-1}背包问题
def DFS(i, n, m, w, v):
global bestV, curW, curV, x, bestx
if i >= n:
if bestV < curV:
bestV = curV
bestx = x[:]
else:
if curW + w[i] <= m:
x[i] = 1
curW += w[i]
curV += v[i]
DFS(i + 1, n, m, w, v)
curW -= w[i]
curV -= v[i]
x[i] = 0
DFS(i + 1, n, m, w, v)
- DP函数:采用动态规划算法求解D{0-1}背包问题
def DP(n, m, w, value):
data = open("C:/Users/涵涵/Desktop/checkresult.txt", "w+")
bagList = [0] * len(w)
x = [0 for i in range(n)]
j = m
# 求出解向量
for i in range(n, 0, -1):
if value[i][j] > value[i - 1][j]:
x[i - 1] = 1
j -= w[i - 1]
for i in range(n):
if x[i]:
bagList[i] = 1
print('最大价值为:', value[n][m])
print('最大价值为:', value[n][m], file=data)
print("解向量:", bagList)
print('解向量:', bagList, file=data)
return value[n][m]
- tanXin函数:采用贪心法求解D{0-1}背包问题
def tanXin(m, h, v):
data = open("C:/Users/涵涵/Desktop/checkresult.txt", "w+")
start = time.time()
arr = [(i, v[i] / h[i], h[i], v[i]) for i in range(len(h))]
arr.sort(key = lambda x: x[1], reverse = True)
bagVal = 0
bagList = [0] * len(h)
for i, w, h, v in arr:
if w <= m:
m -= h
bagVal += v
bagList[i] = 1
else:
bagVal += m * w
bagList[i] = 1
break
6.软件设计的“模块化”实现
模块化: 把程序划分成若干个模块, 每个模块完成一个子功能, 把这些模块集总起来组成一个整体,可以完成指定的功能,满足问题的功能.
实现分析:采用了一个主控程序,编写了贪心法、动态规划算法以及回溯法三个函数实现了{0-1}背包问题的求解,用show函数来绘制散点图,sort函数进行排序,最后使用了save函数保存输出结果,这样使得一个功能较多的程序分解成小块,既能提高工作效率,也能提高软件质量,此外还可以保持系统的可复用性和可维护性
7.PSP展示
PSP2.1 | 任务内容 | 计划完成共需要的时间(min) | 实际完成共需要的时间(min) |
Planning | 计划 | 10 | 10 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 10 | 10 |
Development | 开发 | 260 | 315 |
Analysis | 需求分析(包括学习新技术) | 8 | 10 |
Design Spec | 生成设计文档 | 12 | 20 |
Design Review | 设计复审(和同事审核设计文档) | 5 | 4 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 16 |
Design | 具体设计 | 20 | 25 |
Coding | 具体编码 | 170 | 200 |
Code Review | 代码复审 | 15 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 20 | 10 |
Reporting | 报告 | 40 | 50 |
Test Reporting | 测试报告 | 10 | 15 |
Size Measurement | 计算工作量 | 10 | 8 |
Postmortem & Process Improvenment Plan | 事后总结,并提出过程改进计划 | 20 | 27 |
- 从PSP展示环节可以看到我在开发环节所耗费的时间较多,主要原因是从文件读取数据环节时耗费了较多的时间,在代码规范环节发现了自己的代码存在许多问题,于是花费了较多的随时间进行修改。
8.经验分享
通过此次对《{0-1}背包问题》项目的设计,我先是分析了软件的需求,需要完成哪些功能,在完成整体思路的梳理后。我本来打算用C进行编写,但是突然想起使用python来编写代码可以达到可视化的目的,那么就可以轻易的完成散点图的绘制,导入matplotlib包可以方便的绘制所需的图。此外,学习PSP流程,通过创建PSP,可以更好地了解自己的欠缺之处,提高效率。而模块化编程将大程序按功能可以分成小程序块来实现,不仅提高了效率,同时也方便了代码复审和测试。通过对代码规范的书写,发现了自己对于书写这一块的欠缺,希望以后能不断改进。最后,在互评中我发现每个人的编写习惯都不一样,通过学习他人良好的编写习惯,对于完善自己的博客及代码书写规范有很大的好处。虽然这次作业花费了我不少的时间,但是收获了不少,这次作业激发了我学习的动力。