现代程序设计 homework-02
首先显示博客要求:
描述在这么多相似的需求面前, 你怎么维护你的设计 (父类/子类/基类, UML, 设计模式, 或者其它方法) 让整个程序的架构不至于崩溃的?
建议从后往前来搞,比如我通读一遍需求后了解到后面会用到多种模式,那么在输入的时候自然要定义后mode然后一步一步来,这里用的是面向过程的设计方法,所以没有用到面向对象的那么多冗杂的概念,程序的架构主要是根据不同的mode分别进行相应的输入错误判断,然后调用不同的Input函数完成输入,init()函数完成初始化操作,最后通过不同的work()函数完成函数主体操作
给出你做单元测试/代码覆盖率的最终覆盖率的报告, 用截屏显示你的代码覆盖率
。。。。我的作业2是用C++的面向过程方法写的。。。无法进行单元测试。。。今天我做完了作业3。。。。用C#实现。。。尝试着用单元测试。。。
结果出现了这个东东
难道是告诉我只能有Form类可以进行单元测试么....虽然代码写的偏面向过程....也不用这个样子吧....所以这次没有这一项...或者说这次的代码不适合进行单元测试...我进行了其他方面的测试...证明了我的代码比较挫...至于Bug..从零开始学c#...调Bug 调了两天...应该质量可以的..
阅读 工程师的能力评估和发展 和相关文章, 在完成作业的时候记录自己花费的时间, 并填下表。如果你对有些术语不太清楚,请查看教材和其它资料。如果你认为你不需要做某个步骤, 那就跳过去。
Personal Software Process Stages | 时间百分比(%) | 实际花费的时间 (分钟) | 原来估计的时间 (分钟) | |
Planning | 计划 | 3.3 | 45 | 60 |
· Estimate | · 估计这个任务需要多少时间,把工作细化并大致排序 | 3.3 | 45 | 60 |
Development | 开发 | 81.2 | 1100 | 840 |
· Analysis | · 需求分析 (包括学习新技术) | 4.4 | 60 | 60 |
· Design Spec | · 生成设计文档 | 0 | 0 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 | 0 |
· Coding Standard | · 代码规范 (制定合适的规范) | 0 | 0 | 0 |
· Design | · 具体设计 | 8.9 | 120 | 60 |
· Coding | · 具体编码 | 59.0 | 800 | 600 |
· Code Review | · 代码复审 | 4.4 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 4.4 | 60 | 60 |
Reporting | 总结报告 | 15.5 | 210 | 60 |
· Test Report | · 测试报告 | 8.9 | 120 | 0 |
· Size Measurement | · 计算工作量 | 2.2 | 30 | 0 |
· Postmortem & Improvement Plan | · 事后总结, 并提出改进 | 4.4 | 60 | 60 |
Total | 总计 | 100% | 总用时 | 总估计的用时 |
1355 | 960 |
你在这个作业中学到了什么? 有什么好的设计值得分享? 感想如何 (太容易 / 太难 / 太无趣)?
。。。感想绝对是太难。。
其他的变形还算简单,但是关于最大联通子块自己一直没有想到好的做法,今天想了一天采用状压dp的做法一直无法得出正确的结果,原因在于我是采用按行dp的算法,那么在行与行之间进行转移的时候就出现了问题,我不知道该如何用代码表示两行之间存在相邻关系,这里我用二进制表示一行的状态,某位置0表示该位不取,置1表示该位取,那么对于相邻两行的二进制状态,我该如何表示它们的相邻关系呢?今天这一整天我想了无数的转移方法,但一个个的被我推翻,最后的最后我发现貌似我要采取更暴力的穷举状态了,那就是将每行的状态表示为一个数字,那么所有行的数字按位与之后所得的结果如果不为0就表示它们满足相邻关系,那么我就可以求出一个和,穷举所有行的所有状态,那么就可以求出一个最大值.好可怕的复杂度....记行数为n,每行m个数,那么对每一个行,状态有2^m种,复杂度就是O(2^(mn)),,一会儿去实现一下.
昨晚找鲁大师请教了一下,他和我说这种题目叫做连通性状压dp,也就是插头dp,于是今天上午看了一会儿插头dp,可是这东西完全看不懂啊...代码那么一坨...于是今天思考了一下用暴力来解决这个问题.用01串来标记整个二维数组,枚举每一种状态,判断该状态是否满足连通性条件(采用dfs来判定),然后找最大值就好...复杂度大概为O(2^mn)....
没有用面向对象的思想来做这个问题,导致代码有500行之多...好挫..
吐槽完了,说一下代码思路
首先根据命令行参数的数量以及各个string来判断mode,并且处理错误输入
对于一维和二维普通情况,就是O(n)的最大子数组,方法不过多讲了,参加上一篇博客
1 void maxsum1()//一维O(n)求最大子数组 2 { 3 long long tempsum=num[1]; 4 long long ans=tempsum; 5 for(int i=2;i<=col;i++) 6 { 7 tempsum=max(num[i],tempsum+num[i]); 8 ans=max(tempsum,ans); 9 } 10 printf("%lld\n",ans); 11 }
1 void maxsum2()//二维最大子数组O(n^3) 2 { 3 init2(); 4 int tempans=map[1][1]; 5 int ans=tempans; 6 for(int i=1;i<=row;i++) 7 { 8 for(int j=i;j<=row;j++) 9 { 10 tempans=getsum(i,1,j,1); 11 for(int k=2;k<=col;k++) 12 { 13 tempans=max(getsum(i,k,j,k),tempans+getsum(i,k,j,k)); 14 ans=max(tempans,ans); 15 } 16 } 17 } 18 printf("%d\n",ans); 19 }
对于一维左右联通情况,我们可以知道它的最大和要么是没有跨过了a[n]和a[1],要么是没有跨过;如果没有跨过,那么就是简单的一维普通情况,记最大值为ans1;如果跨过了,那么不妨设此时的最大子数组为a[j],a[j+1],....a[n],a[1],a[2],...a[i],i<j,此时可以证明a[i],a[i+1],....a[j]一定是最小子数组,并且a[i]和a[j]一定是小于0的(否则可以加到最大子数组中得到更优的解),那么我们扫描一遍的时候,只要同时记录最大子数组,最小子数组,和数组总和,那么ans=max(ans1,all-ans2);
对于二维左右联通情况,只要先纵向压缩为一维,然后再调用就好
对于二维上下联通情况,这里我想到了两种解决方法:一是可以在输入的时候将原来的数组转置,那么就变成了求左右联通的情况;二是可以在纵向压缩的时候不必保证上界小于下界,当枚举的下界小于上界的时候,此时的getsum求得的和其实是总的和减去上下界之间的和,然后情况又变成了普通的二维情况
1 void maxsum3()//左右联通情况的最大子数组 2 { 3 init2(); 4 int sum1=sum[1][1]; 5 int sum2=sum[1][1]; 6 int all=sum[1][1]; 7 int tempmin=sum[1][1]; 8 int tempmax=sum[1][1]; 9 int ans=sum[1][1]; 10 for(int i=1;i<=row;i++) 11 { 12 for(int j=i;j<=row;j++) 13 { 14 sum1=sum2=tempmin=tempmax=all=getsum(i,1,j,1); 15 for(int k=2;k<=col;k++) 16 { 17 int temp=getsum(i,k,j,k); 18 all+=temp; 19 sum2=min(sum2+temp,temp); 20 /* 21 if(sum2<0) 22 { 23 sum2+=temp; 24 } 25 else 26 { 27 sum2=temp; 28 } 29 */ 30 tempmin=min(tempmin,sum2); 31 sum1=max(sum1+temp,temp); 32 /* 33 if(sum1>0) 34 { 35 sum1+=temp; 36 } 37 else 38 { 39 sum1=temp; 40 } 41 */ 42 tempmax=max(tempmax,sum1); 43 } 44 ans=max(max(tempmax,all-tempmin),ans); 45 if(tempmin==all) 46 { 47 ans=max(ans,tempmax); 48 } 49 } 50 } 51 printf("%d\n",ans); 52 }
对于游泳圈的情况,就是把前两种总和起来考虑就好
1 void maxsum5()//游泳圈形状的最大子数组 2 { 3 init2(); 4 int sum1=sum[1][1]; 5 int sum2=sum[1][1]; 6 int all=sum[1][1]; 7 int tempmin=sum[1][1]; 8 int tempmax=sum[1][1]; 9 int ans=sum[1][1]; 10 for(int i=1;i<=row;i++) 11 { 12 for(int j=1;j<=row;j++) 13 { 14 sum1=sum2=tempmin=tempmax=all=getsum(i,1,j,1); 15 for(int k=2;k<=col;k++) 16 { 17 int temp=getsum(i,k,j,k); 18 all+=temp; 19 sum2=min(sum2+temp,temp); 20 /* 21 if(sum2<0) 22 { 23 sum2+=temp; 24 } 25 else 26 { 27 sum2=temp; 28 } 29 */ 30 tempmin=min(tempmin,sum2); 31 sum1=max(sum1+temp,temp); 32 /* 33 if(sum1>0) 34 { 35 sum1+=temp; 36 } 37 else 38 { 39 sum1=temp; 40 } 41 */ 42 tempmax=max(tempmax,sum1); 43 } 44 ans=max(max(tempmax,all-tempmin),ans); 45 if(tempmin==all) 46 { 47 ans=max(ans,tempmax); 48 } 49 } 50 } 51 printf("%d\n",ans); 52 /* 53 for(int i=1;i<=row;i++) 54 { 55 int len=(i>1?row-1:row); 56 for(int j=i;j-i<len;j++) 57 { 58 int begin=1; 59 int temp=0; 60 for(int end=1;end<col*2&&begin<=col;end++) 61 { 62 if(end-begin>=col) 63 { 64 end=++begin; 65 temp=0; 66 } 67 temp=max(0,temp+sum[j][end]-sum[i-1][end]); 68 if(temp<=0) 69 { 70 begin=end+1; 71 } 72 if(temp>ans) 73 { 74 ans=temp; 75 } 76 } 77 } 78 } 79 printf("%d\n",ans); 80 */ 81 }
对于联通块,我的朴素解法已经在上面说明了,对于更高效率的插头dp解法我不会
1 bool check(int x,int y) 2 { 3 if(x<0||x>=row||y<0||y>=col) 4 { 5 return false; 6 } 7 else 8 { 9 return true; 10 } 11 } 12 void dfs(int x,int y,int choice) 13 { 14 visit[x][y]=1; 15 for(int i=0;i<4;i++) 16 { 17 int tx=choice?(x+dx[i]+row)%row:x+dx[i]; 18 int ty=choice?(y+dy[i]+col)%col:y+dy[i]; 19 if(check(tx,ty)&&!visit[tx][ty]&&bit[tx][ty]) 20 { 21 dfs(tx,ty,choice); 22 } 23 } 24 } 25 void anotherwork(int choice) 26 { 27 int ans=-INF; 28 for(int i=0;i<row;i++) 29 { 30 for(int j=0;j<col-1;j++) 31 { 32 if(scanf_s("%d,",&map[i][j])!=1) 33 { 34 printf("input matrix wrong!\n"); 35 exit(0); 36 } 37 } 38 if(scanf_s("%d",&map[i][col-1])!=1) 39 { 40 printf("input matrix wrong!\n"); 41 exit(0); 42 } 43 } 44 int N=row*col; 45 for(int i=0;i<(1<<N);i++)//枚举2^nm种状态 46 { 47 for(int j=0;j<row;j++) 48 { 49 for(int k=0;k<col;k++) 50 { 51 visit[j][k]=0; 52 bit[j][k]=0; 53 } 54 } 55 for(int j=0;j<N;j++) 56 { 57 bit[j/col][j%col]=(i&(1<<j))>>j; 58 } 59 bool ok=true; 60 for(int j=0;j<row;j++) 61 { 62 if(!ok) 63 { 64 break; 65 } 66 for(int k=0;k<col;k++) 67 { 68 if(bit[j][k])//找到第一个1点进行dfs标记该联通块 69 { 70 dfs(j,k,choice); 71 ok=false; 72 break; 73 } 74 } 75 } 76 ok=true; 77 for(int j=0;j<row;j++) 78 { 79 if(!ok) 80 { 81 break; 82 } 83 for(int k=0;k<col;k++) 84 { 85 if(bit[j][k]&&!visit[j][k]) 86 { 87 ok=false; 88 break; 89 } 90 } 91 } 92 int s=-INF; 93 if(ok) 94 { 95 s=0; 96 for(int j=0;j<row;j++) 97 { 98 for(int k=0;k<col;k++) 99 { 100 if(bit[j][k]) 101 { 102 s+=map[j][k]; 103 } 104 } 105 } 106 ans=max(ans,s); 107 } 108 } 109 printf("%d\n",ans); 110 }
PS:作业有要求对于错误输入要能够正确处理,结果我写了一个巨长的处理函数处理了未输入指定分隔符;输入数据不够多;输入数据太多===是不是想太多了..