201971010146-杨凯 实验二 软件项目工程个人项目 《0-1背包问题》项目报告
201971010146-杨凯 实验二 软件工程个人项目 《0-1背包问题》项目报告
项目 | |
---|---|
课程班级博客链接 | [2022年春软件工程课程班(2019级计算机科学与技术)](首页 - 2022年春软件工程课程班(2019级计算机科学与技术) - 西北师范大学 - 班级博客 - 博客园 (cnblogs.com)) |
这个作业要求链接 | [实验二 软件工程个人项目 ](实验二 软件工程个人项目 - 作业 - 2022年春软件工程课程班(2019级计算机科学与技术) - 班级博客 - 博客园 (cnblogs.com)) |
我的课程学习目标 | (1) 掌握软件项目个人开发流程 (2) 掌握Github发布软件项目的操作方法 |
帮助我实现学习目标 | (1) 掌握了psp流程 (2) 掌握了Github发布软件项目的操作方法 (3) 复习了背包问题的各种解决方法 |
项目Github的仓库链接 | KP项目 |
任务1:
- [点评链接1](201971010131-李治江 实验一 软件工程准备—课程学习准备 - bkbkb - 博客园 (cnblogs.com))
- 点评: 排版整洁,第三个问题对计算机科学与软件工程的区别做出了良好的划分。希望你在之后的学习中,能够更加认真努力!!!
- [点评链接2](201971010118-梁春云 实验一 软件工程准备-认识及学习软件工程 - 梁春云 - 博客园 (cnblogs.com))
- 点评:博主提出的问题简洁明练,可以看出是对问题的研究很透彻的。
- [点评链接3](201971010125-李涛 实验一 软件工程准备—课程导学 - 李涛。 - 博客园 (cnblogs.com))
- 点评:确实引人深思,模块之间如果说互相不影响,会不会使得代码性能更加优化呢
任务2(构建之法第一、二章总结):
第一章:
- 软件 = 程序 + 软件工程(软件企业 = 软件 + 商业模式 )
- 软件的生命周期: 软件需求、软件设计、软件构造、软件测试、软件维护。
- 软件工程:软件工程是把系统的、有序的、可量化的方法应用到软件的开发、运营和维护上的过程。
- 软件工程包括下列领域:
- 软件需求分析
- 软件设计
- 软件构建
- 软件测试
- 软件维护。
- 软件工程和下列的学科相关:
- 计算机科学
- 计算机工程
- 管理学
- 数学
- 项目管理学
- 质量管理
- 软件人体工学
- 系统工程
- 工业设计和用户体验设计。
- 软件的特殊性:复杂性、不可见性、易变性、非连续性。
- 软件工程的目标:创造出用户满意度高,可靠性高,软件流程质量高,可维护性高的软件。
第二章(个人技术和流程):
-
效能分析工具:
- 抽样:
- 代码注入
-
PSP有如下的特点:
1. 不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这样,开发不同应用的软件工程师可以互相比较;
2. 不依赖于考试,而主要靠工程师自己收集数据,然后分析,提高;
3. 在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输入质量不高。在这种情况下,程序员的输出(程序/软件)往往质量也不高,然而这并不能全部由程序员负责;
4. PSP依赖于数据:
需要工程师输入数据,记录工程师的各项活动,这本身就需要不小的时间代价
如果数据不准确或有遗失,怎么办?让工程师编造一些?
如果一些数据不利于工程师本人(例如:花很多时间修改缺陷),我们怎么能保证工程师愿意如实地记录这些数据呢?
5. PSP的目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度。
任务3(项目开发):
一、 需求分析:
- 使用贪心算法,动态规划算法,回溯算法求解(0-1)背包问题。
- 正确读入实验数据文件有效KP数据。
- 绘制某组KP数据以价值重量为横轴,价值为纵轴的数据散点图。
- 能够对一组KP数据按重量比进行非递增排序。
- 用户能够自主选择贪心算法、动态规划算法、回溯法。
- 任意一组KP数据的最优解,求解时间保存到文件中。
二、 功能设计:
三、 设计实现:
1. 读入实验数据文件:
FILE *fp;
char filename[30],x[31];
cout<<"测试文件:\n";
cout<<"beibao0.in\nbeibao1.in\nbeibao2.in\nbeibao3.in\n";
cout<<"beibao4.in\nbeibao5.in\nbeibao6.in\nbeibao7.in\nbeibao8.in\nbeibao9.in\n";
cout<<"请输入测试数据文件名(带后缀):\n";
gets(filename);
if((fp=fopen(filename,"r+"))==NULL){
printf("ERROR!\n");
exit(0);
}
fscanf(fp,"%d %d", &C, &n);
printf("背包容量为: %d,物品个数为: %d\n", C, n);
for(int i = 0; i < n; i++)
{
fscanf(fp, "%d %d",&goods[i].wight,&goods[i].value);
printf("%d %d\n", goods[i].wight,goods[i].value);
}
从文件中读取数据采用了c++的文件输入输出流,从键盘中获取到文件名之后,采用fopen(filename, "r+")打开文件,然后逐行读取。
2.用户自主选择算法:
使用switch语句:
switch(x){
case 1:
动态规划算法···
break;
case 2:
贪心算法···
break;
case 3:
回溯算法···
break;
}
- 动态规划算法:
int KnapSack2(int n,struct goods a[],int C,int x[]){
int V[N][10*N];
for(int i = 0; i <= n; i++)//初始化第0列
V[i][0] = 0;
for(int j = 0; j <= C; j++)//初始化第0行
V[0][j] = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= C; j++)
if(j < a[i-1].wight)
V[i][j] = V[i-1][j];
else
V[i][j] = MAX(V[i-1][j],V[i-1][j-a[i-1].wight] + a[i-1].value);
for(int i = n,j = C; i > 0; i--){
if(V[i][j] > V[i-1][j]){
x[i-1] = 1;
j = j - a[i-1].wight;
}
else
x[i-1] = 0;
}
return V[n][C];
}
- 贪心算法:
int KnapSack1(int i){
if(i>n-1){
if(bestValue < cv && cw + goods[i].wight <= C){
for(int k=0;k<n;k++)
X[k] = cx[k];//存储最优路径
bestValue = cv;
}
return bestValue;
}
cw = cw + goods[i].wight;
cv = cv + goods[i].value;
cx[i] = 1;//装入背包
KnapSack1(i+1);
cw = cw-goods[i].wight;
cv = cv-goods[i].value;
cx[i] = 0;//不装入背包
KnapSack1(i+1);
return bestValue;
}
- 回溯算法:
int BackTrack(int i){
if(i > n-1){
if(bestValue < cv){
for(int k = 0; k < n; k++)
X[k] = cx[k];//存储最优路径
bestValue = cv;
}
return bestValue;
}
if(cw + goods[i].wight <= C){//进入左子树
cw += goods[i].wight;
cv += goods[i].value;
cx[i] = 1;//装入背包
BackTrack(i+1);
cw -= goods[i].wight;
cv -= goods[i].value;//回溯,进入右子树
}
cx[i] = 0;//不装入背包
BackTrack(i+1);
return bestValue;
}
bool m(struct goods a, struct goods b){
return (a.value/a.wight) > (b.value/b.wight);
}
int KnapSack3(int n, struct goods a[], int C,int x[N]){
memset(x,0,sizeof(x));
sort(a,a+n,m);//将各物品按单位重量价值降序排列
BackTrack(0);
return bestValue;
}
3. KP数据最优解及运行时间保存到文件:
-
最优解和运行时间的计算
-
最优解的计算:
获取三个算法所求得的bestValue返回输出。
-
运行时间的计算:
需要用到:
#include <time.h> #include <windows.h> #include <stdio.h>
三个库函数,然后用结束运行的时间减去开始运行的时间就是运行的时间:
time(&start); ···代码运行··· time(&end); cost=difftime(end,start)
-
-
最优解和运行时间的保存:
ofstream outfile; outfile.open("beibao.out"); outfile<<sum2<<" 运行时间: "<<cost<<endl; outfile.close();
4. 对一组KP数据按照重量比进行非递增排序:
int KnapSack3(int n, struct goods a[], int C,int x[N]){
memset(x,0,sizeof(x));
sort(a,a+n,m);//将各物品按单位重量价值降序排列
BackTrack(0);
return bestValue;
}
四、测试运行
1. 读入实验数据及算法选择:
2. 输出结果保存到文件中:
五、代码
int KnapSack3(int n, struct goods a[], int C,int x[N]){
memset(x,0,sizeof(x));
sort(a,a+n,m);//将各物品按单位重量价值降序排列
BackTrack(0);
return bestValue;
}
FILE *fp;
char filename[30],x[31];
cout<<"测试文件:\n";
cout<<"beibao0.in\nbeibao1.in\nbeibao2.in\nbeibao3.in\n";
cout<<"beibao4.in\nbeibao5.in\nbeibao6.in\nbeibao7.in\n";
cout<<"请输入测试数据文件名(带后缀):\n";
gets(filename);
if((fp=fopen(filename,"r+"))==NULL){
printf("ERROR!\n");
exit(0);
}
fscanf(fp,"%d %d", &C, &n);
printf("背包容量为: %d,物品个数为: %d\n", C, n);
for(int i = 0; i < n; i++)
{
fscanf(fp, "%d %d",&goods[i].wight,&goods[i].value);
printf("%d %d\n", goods[i].wight,goods[i].value);
}
七、PSP
PSP2.1 | 任务内容 | 计划共完成需要的时间(min) | 实际共完成需要的时间(min) |
---|---|---|---|
planning | 计划 | 5 | 15 |
Estimate | 估计这个任务需要多少时间,并规划大致步骤 | 10 | 5 |
Development | 开发 | 700 | 807 |
Analysis | 需求分析(包括学习新技术) | 30 | 60 |
Design Spec | 生成设计文档 | 20 | 35 |
Design Review | 设计复审(和同事核审设计文档) | 5 | 7 |
Coding Standard | 代码规范(为目前的开发制定合适的规范) | 10 | 20 |
Design | 具体设计 | 120 | 100 |
Coding | 具体编码 | 120 | 240 |
Code Review | 代码复审 | 50 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 100 | 120 |
Reporting | 报告 | 60 | 100 |
Test Report | 测试报告 | 30 | 20 |
Size Measurement | 计算工作量 | 10 | 15 |
Postmortem &Process Improvement Plan |
事后总结,并提出过程改进计划 | 20 | 30 |
八、经验分享;
本次实验刚布置下来的时候我就感觉到了难度,可能跟自己前几个学期没有好哈学习有关,导致现在对贪心算法,回溯算法,动态规划算法不太熟悉和理解,花费了大量的时间来弄懂这个几个算法。我想之前的学习要是能够扎实一点,会比较好一点。
在完成项目的过程中,我对项目的完成也有了自己的计划,我发现有一个比较好的计划,是很重要的,不能随便像无头的苍蝇一样乱来,有条不紊才能加快项目完成的进度以及效率。
多尝试着自己写代码,可以百度一下,但不要照搬照抄,可以对别人的方法进行采纳。不尝试自己写代码,是永远不会写代码的。
在写代码的时候,才发现自己好多语法的细节并不理解,只知道大概,并没有深入学习,导致一知半解。所以在学习的时候还是得注重细节,注重基础。基础牢靠才能越走越高。