201871010114-李岩松 实验二 个人项目—《D{0-1}KP》项目报告

项目 内容
课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST
这个作业要求链接 https://www.cnblogs.com/nwnu-daizh/p/14552393.html
我的课程学习目标 1.掌握GitHub的基本操作
2.掌握软件项目个人开发的流程
3.完成D{0-1}KP问题个人开发项目(符合代码规范)
这个作业在哪些方面帮助我实现学习目标 1.阅读《构建之法》第1章、第二章
2.将自己的项目发布到Github上,commit不低于10次
3.个人项目D{0-1}KP问题的开发
4.个人项目PSP流程
项目Github仓库地址 https://github.com/liyansong0198/D-01-KP

任务1:阅读教师博客“常用源代码管理工具与开发工具”内容要求,点评班级博客中已提交相关至少3份作业

任务2:详细阅读《构建之法》第1章、第2章,掌握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}背包问题的程序,程序基本功能要求如下:
    • 可正确读入实验数据文件的有效D{0-1}KP数据;
    • 能够绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图;
    • 能够对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序;
    • 用户能够自主选择动态规划算法、回溯算法求解指定D{0-1} KP数据的最优解和求解时间(以秒为单位);
    • 任意一组D{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件或导出EXCEL文件。

任务4:完成任务3的程序开发,将项目源码的完整工程文件提交到你注册Github账号的项目仓库中。

完成项目过程:

  • 任务需求分析:
    对于本次个人项目求解D{0-1}KP问题,根据程序的基本功能要求做出如下分析:
    对于本次问题的求解,最开始看到散点图的绘制,就想到了以前在数据分析可视化Python中matplotlib库,用于绘制散点图,同时Python的文件读取也是十分方便,可以采用Python编程语言进行开发,与此同时对五个任务的求解做出如下分析

    1. 对于本次任务数据读取的处理,不同于普通的背包问题,每一组的数据集需要将其处理成以三个数据为一组的二维列表,可以通过文件将其按行读入,包含关键字匹配后去除换行符对其进行数据分割,生成分别为profit和weight的三位列表,输出数据并为后面问题求解的数据进行处理生成相应的列表
    2. 对于第二个功能的求解,调用Python库当中的matplotlib库中的scattar()函数,将传入的数组列表进行数据分割,进行绘制即可
    3. 对于功能3的求解,将第一问读入的数据处理成三维列表,第一维列表中的每个列表有9个数据,分别是读入数据的三个的重量、价格和重量价格比值,调用sort函数进行求解
    4. 对于功能4,需要调用回溯算法,需要确定好回溯算法中递归的条件,递归算法的分析,对回溯出来结果进行排序,然后就会得到最优解,调用动态规划算法的求解需要确定好最后一步以及状态方程的样子,该问题为分组背包问题,在前期的学习中需要注意状态方程的推导,对于运行时间可以采用运行回溯或者动态规划函数前的时间和函数结束后的时间差,求得求解时间、同样试用动态规划算法主要是该算法的状态方程
    5. 对于功能5只需要将求解得到的结果进行调用write函数进行写操作即可
    6. 学习任务:回溯算法、动态规划问题的求解
  • 功能设计
    1. 正确读入实验数据文件的有效D{0-1}KP数据
    2. 能够绘制任意一组D{0-1}KP数据以重量为横轴、价值为纵轴的数据散点图
    3. 使用回溯算法、动态规划算法求解指定D{0-1} KP数据的最优解和求解时间
    4. 任意一组D{0-1} KP数据的最优解、求解时间可保存为txt文件
    5. 能够对一组D{0-1}KP数据按项集第三项的价值:重量比进行非递增排序

  • 设计实现
    D{0-1}问题求解过程设计函数如下图所示,主要由四个函数构成来实现问题求解的过程

    1.getdata函数功能:

      #************************************************************************
      #   Description:按行读入实验数据文件的有效D{0-1}KP数据,以三个为一组打印输入数据集的
      #   重量、价格,九个为一组的价格重量和价格比重量
      #   Input:textname数据集的文件名称
      #   Output:
      #   Return:
      #   others
      #************************************************************************
      def getdata(textname):
          file = open(textname)
          line = file.readline()
          while line:
              # print(line, end='')  # end = ''表示不换行
              # print(line)  # 默认换行
              line = file.readline()
              if line.__contains__("profit"):
                  profitdata=re.sub('[.
    ]', '', file.readline()).strip(',')
                  profitdata_list.append(profitdata)
              elif line.__contains__("weight"):
                  weightdata=re.sub('[.
    ]', '', file.readline()).strip(',')
                  #print(weightdata)
                  weightdata_list.append(weightdata)
          for i in range(len(profitdata_list)):
              temporary_profit_list=[]
              temporary_weight_list=[]
              temporary_pw_radio_list = []
              three_profit_list = []
              three_weight_list = []
              three_pw_radio_list = []
              num=0
              profit_list = str(profitdata_list[i]).split(',')
              weight_list = str(weightdata_list[i]).split(',')
              for j in range(len(weight_list)):
                  three_profit_list.append(int(profit_list[j]))
                  three_weight_list.append(int(weight_list[j]))
                  three_pw_radio_list.append(int(profit_list[j])/int(weight_list[j]))
                  num=num+1
                  if num==3:
                      temporary_profit_list.append(three_profit_list)
                      temporary_weight_list.append(three_weight_list)
                      temporary_pw_radio_list.append(three_profit_list+three_weight_list+three_pw_radio_list)
                      three_profit_list = []
                      three_weight_list = []
                      three_pw_radio_list = []
                      num=0
              profit_end_list.append(temporary_profit_list)
              weight_end_list.append(temporary_weight_list)
              profit_weight_pwradio_list.append(temporary_pw_radio_list)
          print('数据读取成功!')
          print('数据读取结果如下')
          print('重量')
          print(profit_end_list)
          print('价值')
          print(weight_end_list)
          print('重量/价值/重量:价值系数')
          print(profit_weight_pwradio_list)
    

    2.pwscattar函数功能:

    3.recall函数功能:

    recall函数流程图

    recall函数主要实现回溯算法

    #************************************************************************
    #   Description:使用回溯算法求解指定D{0-1} KP数据的最优解和求解时间
    #   Input: max_hieght:背包的最大容量 x:列表的一维下标 y:列表的二维下标
    #   totalprofit:背包中总价值 totalweight:背包中总重量
    #   Output:
    #   Return:
    #   others:
    #************************************************************************
    def recall(max_height,x,y,new_profit,new_weight,totalprofit,totalweight):
      if y != 3:
          totalprofit=totalprofit+new_profit[x][y]
          totalweight=totalweight+new_weight[x][y]
      if totalweight>max_height:
          return 0
      if x == len(new_profit)-1:
          ret.append(totalprofit)
          return 0
      for i in range(4):
          recall(max_height,x+1,i,new_profit,new_weight,totalprofit,totalweight)
      return 0
    

    4.pwsort函数

    def pwradio_sort(n):
        twp_sort=sorted(profit_weight_pwradio_list[n], key=operator.itemgetter(-1), reverse=True)
        print(twp_sort)
    
  • 测试运行
    1. 读取文本数据并处理

    2. 绘制散点图

    3. 回溯算法求解分组背包问题

    4. 动态规划算法求解分组背包问题

    5. 三元组最后一项价值/重量排序

    6. 输出结果为txt

  • 本次个人项目PSP

PSP2.1 任务内容 计划共完成需要的时间(h) 实际完成需要的时间(h)
Planning 计划 2 1.5
·       Estimate ·  估计这个任务需要多少时间,并规划大致工作步骤 2 1.5
Development 开发 35 49
··       Analysis 需求分析 (包括学习新技术) 10 12.5
·       Design Spec ·  生成设计文档 2 2
·       Design Review ·  设计复审 (和同事审核设计文档) 1 0.5
·       Coding Standard 代码规范 (为目前的开发制定合适的规范) 1 1
·       Design 具体设计 2 5
·       Coding 具体编码 8 15
·       Code Review ·  代码复审 3 3
·       Test ·  测试(自我测试,修改代码,提交修改) 8 10
Reporting 报告 3.5 2
··       Test Report ·  测试报告 2 1
·       Size Measurement 计算工作量 1 1
·       Postmortem & Process Improvement Plan ·  事后总结 ,并提出过程改进计划 0.5 1
  • 项目总结
    本次个人项目D{0-1}问题的求解整个过程当中充满了挑战和学习的内容,对于项目要求博文发布的时候,脑子里面一头污水,只想着去学习回溯算法,动态规划算法,根本忽视了这门课的本质,需要完成个人的PSP,在中期代老师上课突发性的检查自己项目的PSP时,发现自己的个人项目缺乏最基本的个人项目开发的流程,由于自己本身算法和编码能力的底子很差,回到宿舍一直都在一起讨论整个项目开发的流程、算法的思想、解题步骤,具体的算法设计。
    在上周四的晚上制定好了本次个人开发项目的PSP,开始进行问题求解设计和编码,最后经过努力还是对基本功能的实现中的动态规划算法测试还是有bug但是回溯算法已经实现,基本的五个功能虽说有所差距,体会到了自己努力编码和整体软件工程的方法指导是密不可分的,本次项目中时间差距最大的还是编码部分,由于在前期需求分析阶段,对回溯和动态规划算法理解不清楚,设计和编码的时候,浪费了很多的时间去调试代码,重新分析算法、设计算法,最后在和舍友的交流和反思自己编码的内容的时候得到DP{0-1}背包问题的编码实现,本次个人项目收获很大,期待后期的努力和更大的进步
  • Github提交过程

原文地址:https://www.cnblogs.com/liyansong0198/p/14599939.html