201871010128-杨丽霞 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

项目 内容
课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST
这个作业要求链接 https://www.cnblogs.com/nwnu-daizh/p/14604444.html
我的课程学习目标 (1)理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念
(2)掌握软件项目个人开发流程,并开发出个人的软件项目
(3)掌握Github发布软件项目的操作方法,并将自己的软件项目发布于Github
这个作业在哪些方面帮助我实现学习目标 (1)理解了代码风格规范、代码设计规范、代码复审、结对编程的概念
(2)在具体的软件项目实施中应用结对编程,在合作中如何高效完成任务
(3)了解了遗传算法,利用遗传算法求解D{0-1}KP
结对方学号-姓名 201871010131-张兴盼
结对方本次博客作业链接 https://www.cnblogs.com/zxp19990614/p/14629135.html
本项目Github的仓库链接地址 地址

实验内容

任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念。

  • (1)代码风格规范:主要是文字上的规定。代码风格的原则是:简明、易读、无二义性,包括对于缩进、行宽、括号、分行、命名、下划线、注释、大小写以及断行与空白的{}行的处理。缩进限定为100字符,复杂的条件表达式中,用括号表示逻辑优先级,有清晰的断行和分行;命名应该遵循规则,简洁易懂。

  • (2)代码设计规范:牵扯到程序设计、模块之间的关系、设计模式等。比如针对函数,他的最重要的原则就是:只做一件事,并且要做好。可以使用goto实现单一的出口。还有错误处理方面的一些内容,比如断言的正确使用等规范。

  • (3)代码复审:看代码是否在代码规范的框架内正确地解决了问题。代码复审的三种形式:自我复审、同伴复审、团队复审。目的是找出代码错误、发现逻辑错误、发现算法错误、发现潜在的错误和回归性错误、发现可能需要改进的地方、传授经验;代码复审后把记录整理出来:更正明显的错误、记录无法很快更正的错误、把所有的错误记在自己的一个“我常犯的错误”表中,作为以后自我复审的第一步。

  • (4)结对编程:结对编程是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。
    在结对编程中,观察员同时考虑工作的战略性方向,提出改进的意见,或将来可能出现的问题以便处理。这样使得驾驶者可以集中全部注意力在完成当前任务的“战术”方面。观察员当作安全网和指南。结对编程对开发程序有很多好处。比如增加纪律性,写出更好的代码等,结对编程是极端编程的组成部分。

任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价。

  • 对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。

  • 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。

  • 依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。

任务3:采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台。
(1)平台基础功能:实验二 任务3;
(2)D{0-1}KP 实例数据集需存储在数据库;
(3)平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
(4)人机交互界面要求为GUI界面(WEB页面、APP页面都可);
(5)查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
(6)附加功能:除(1)-(5)外的任意有效平台功能实现。

  • 需求分析陈述。
    从给定的文件中读取出正确的数据并保存到数据库,绘制散点图,实现对自定义数据类型的列表的排序,解决D{0-1}背包问题的动态规划和回溯算法,将求解后的数据写入文件并保存,接收用户发送的算法文件并运行,将运行结果保存到文件,并且用遗传算法求解D{0-1}KP问题。

  • 软件设计说明。
    目前,求解折扣{0-1}背包问题(D{0-1}KP)的主要算法是基于动态规划的具有伪多项式时间的确定性算法,当D{0-1}KP实例中各项的价值系数与重量系数在大范围内取值时缺乏实用性.文中基于杰出者保留策略遗传算法(EGA)求解D{0-1}KP,首先建立了D{0-1}KP的两个新的数学模型;然后,为了利用EGA和第一数学模型求解D{0-1}KP,提出了一种处理非正常编码个体的贪心修复与优化算法GROA,并将其与EGA相结合给出了求解D{0-1}KP的第一遗传算法FirEGA;紧接着,利用EGA和第二数学模型求解D{0-1}KP,提出了处理非正常编码个体的另一种有效算法NROA,并将其与EGA相结合给出了求解D{0-1}KP的第二遗传算法SecEGA;最后,利用四类大规模D{0-1}KP实例,确定了FirEGA和SecEGA的交叉概率与变异概率的合理取值,比较了两个算法的实际求解性能.对四类实例的计算结果表明:FirEGA和SecEGA都非常适于求解大规模的难D{0-1}KP实例,均能够得到一个近似比非常接近于1的近似解,并且FirEGA的平均求解性能比SecEGA的更优.

  • 软件实现及核心功能代码展示:软件包括哪些类,这些类分别负责什么功能,他们之间的关系怎样?类内有哪些重要的方法,关键的方法是否需要画出流程图?

  • 程序运行:程序运行时每个功能界面截图。扩展功能实现可得附加分5分。

  • 描述结对的过程,提供两人在讨论、细化和编程时的结对照片(非摆拍)。

  • 提供此次结对作业的PSP。

PSP 各个阶段 我们预估的时间(小时) 实际的记录(小时)
计划: 明确需求和其他因素,估计以下的各个任务需要多少时间 1 1
开发 5 7
需求分析 3 4
生成设计文档 1 1
设计复审 3 3
代码规范 4 3
具体设计 5 4
具体编码 6 10
代码复审 1 2
测试 1 1
报告 1 1
测试报告(发现了多少bug,修复了多少) 3 4
事后总结, 并提出改进计划 (包括写文档、博客的时间) 1 1
总共花费的时间 (小时) 35 42

*小结感受:两人合作真的能够带来1+1>2的效果吗?通过这次结对合作,请谈谈你的感受和体会
通过此次的结对编程,感受到两人合作能够带来1+1>2的效果,因为在软件项目的实施过程中,遇到的问题可以有两种不同的思路,通过双方的交流可以解决自己不懂的问题,并且在结对编程中可能会遇到分歧,此时就需要认真听取对方意见,最后就采取两人都觉得可行的结果,在编程中,相互讨论,可以更快更有效地解决问题,互相请教对方,可以得到能力上的互补,并且互相监督,不容易偷懒,两个人一起工作需要互相配合,如果想偷懒去干别的,就会拖延工作进度,两人互相监督工作,可以增强代码和产品质量,并有效的减少错误。在此次的合作过程中我发现自己的对算法的了解以及编程能力都很有限,在之后的学习中要多加强在这方面的练习。
遗传算法:

#include <bits/stdc++.h>
using namespace std;
const int item_num = 8; //物品数量
const int weight_max = 100; //最大重量
const int maxn = 30; //种群数量
const double d = 0.1; //常数(用于惩罚)
const double pc = 0.8; //交叉概率
const double pm = 0.06; //变异概率
const int iteration = 500;
int sum = 0;
typedef struct population
{
int item[item_num];
int value;
int weight;
double fit;
}pop;
int wei[item_num] = {30, 40, 20, 5, 15, 60, 25, 10};
int val[item_num] = {47, 30, 9, 8, 15, 66, 12, 11};
int quanju_best_value = 0;
int quanju_best_weight = 0;
int quanju_best_fitness = 0;
int arr[item_num];
int index = 0;
void Init_population(pop p[])
{
for(int i = 0; i < maxn; i++)
{
for(int j = 0; j < item_num; j++)
p[i].item[j] = rand() % 2;
}
}
//适应度函数
void fitness(pop p[])
{
for(int i = 0; i < maxn; i++)
{
int value_sum = 0, weight_sum = 0;
for(int j = 0; j < item_num; j++)
{
if(p[i].item[j] == 1)
{
value_sum += val[j];
weight_sum += wei[j];
}
}
p[i].value = value_sum;
p[i].weight = weight_sum;
/*
如果该个体重量小于等于100,则其适应度函数为该个体方案的价值,并未改变;
而如果该个体重量超过100,则让其适应度fit = value_sum * d;其中,d是很小的数,且d < 0,
即降低其适应度,那么在后面进行选择时,它被选择的概率就变的很小,即实现惩罚目的。
*/
if(weight_sum <= weight_max)
{
p[i].fit = value_sum;
}
else //惩罚
{
p[i].fit = value_sum * d;
}
}
}

bool cmp(pop a, pop b){
if(a.fit > b.fit) return true;
else return false;
}
//选择
void Select(pop p[])
{
int i;
double choice_pro[maxn]; //每个个体选择机会
double sum_fit = 0; //总适应度
double average_fit = 0; //平均适应度
for(int i = 0; i < maxn; i++)
sum_fit += p[i].fit;
sort(p, p + maxn, cmp);
average_fit = (unsigned int)((sum_fit / maxn) + 0.5); //计算出平均适应值
for (i = 0; i < maxn; i++) //计算每个群体的选择机会
{
//种群个体的概率 = 个体适应度/总适应度 平均概率 = 平均适应度/总适应度 个体被选择机会 = (个体的概率/平均概率)
choice_pro[i] = ((double)p[i].fit / sum_fit) / (average_fit / sum_fit);
choice_pro[i] = (double)((int)(choice_pro[i] * 100 + 0.5) / 100.0);//保留到小数点后2位,四舍五入
}
//根据选择概率来繁殖(copy)优良个体、淘汰较差个体 如果choicePro[i]==0淘汰复制一次最优的群体
for (i = 0; i < maxn; i++)
{
if (((int)(choice_pro[i] + 0.55)) == 0)
p[maxn - 1] = p[0];
}
}

//交叉
void Crossover(pop p[])
{
int n = maxn;
while(n--)
{
int num = rand() % 100;
if(num <= pc * 100){
int ia = 0, ib = 0;
while(ia == ib)
{
ia = rand() % maxn;
ib = rand() % maxn;
}
int a = 0, b = 0;
while(a == b || a > b)
{
a = rand() % item_num;
b = rand() % item_num;
}
for(int i = a; i < b; i++)
{
int temp = p[ia].item[i];
p[ia].item[i] = p[ib].item[i];
p[ib].item[i] = temp;
}
}
}
}
//变异
void Mutation(pop p[])
{
for(int i = 0; i < maxn; i++){
int a = rand() % 100;
if(a <= pm * 100){
int b = rand() % item_num;
if(p[i].item[b] == 1)
p[i].item[b] = 0;
else
p[i].item[b] = 1;
}
}
}


int main()
{
pop p[maxn];
memset(arr, 0, sizeof(arr));
srand((unsigned)time(NULL));
Init_population(p);
int cnt = 0;
while(cnt < iteration)
{
fitness(p);
int jubu_best_value = 0;
int jubu_best_weight = 0;
int jubu_best_index = 0;
double jubu_best_fitness = 0;
for(int i = 0; i < maxn; i++)
if(p[i].fit > jubu_best_fitness)
{
jubu_best_fitness = p[i].fit;
jubu_best_value = p[i].value;
jubu_best_weight = p[i].weight;
jubu_best_index = i;
}
if(jubu_best_value == quanju_best_value) sum++;
cout<<"第"<<cnt + 1<<"代, 最优解为:"<<endl;
cout<<"价值:"<<jubu_best_value<<",重量:"<<jubu_best_weight<<endl;
cout<<"方案:";
for(int i = 0; i < item_num; i++)
if(p[jubu_best_index].item[i] == 1)
{
cout<<i + 1<<" ";
}
if(jubu_best_fitness > quanju_best_fitness)
{
index = cnt + 1;
quanju_best_fitness = jubu_best_fitness;
quanju_best_value = jubu_best_value;
quanju_best_weight = jubu_best_weight;
for(int i = 0; i < item_num; i++)
arr[i] = p[jubu_best_index].item[i];
}
Select(p);
Crossover(p);
Mutation(p);
cnt++;
}
cout<<"全局最优解为:"<<endl;
cout<<"价值:"<<quanju_best_value<<",重量:"<<quanju_best_weight<<endl;
cout<<"方案:";
for(int i = 0; i < item_num; i++)
if(arr[i] == 1)
cout<<i + 1<<" ";
cout<<endl;
cout<<"最优解在第"<<index<<"代产生"<<endl;
cout<<"迭代次数为:"<<iteration<<", 最优解次数为:"<<sum<<",收敛率为:"<<((double)sum / iteration) * 100<<"%"<<endl;
}
posted on 2021-04-14 09:53  杨丽霞  阅读(222)  评论(0编辑  收藏  举报