先谈谈感想
这次作业是第一次作业的一个拓展,本以为至少会思路比较清晰,可谁想到,清晰的只是第二问,问题到了第三问(即关于“/a”),貌似就突然由量变到了质变,该算法貌似到了一个我难以企及的高度。笔者思索了近一个星期,零零碎碎的时间加起来估摸着得有6-7个小时,去思考关于第三问的算法。可结果,算法复杂度依旧是那么的不喜人。没办法,只好去询问一些知名的大神,特此,才勉强得出一个看得过去的算法。但是暂时依旧没能算法实现,在此只提下算法的思想,具体的代码实现由后续的版本持续更新。
第三问算法思想
第三问的思想,我问了很多大神,有些人告诉我用连通性状态压缩,有些人告诉我直接暴力搜索。经过众多大神的指导与启发,我知道了一种用贪心加暴搜的方法,可以在原有的暴搜基础上,通过贪心优化,再此特别感谢梁杰大神。
算法核心思想如下:
1. 定义基点的概念。每一个连通图,对应的由一个起始点发展起来,这个起始点就叫做基点。定义新的数据结构dot,为二维数组中纵坐标,横坐标,以及在数组中的值。
2. 第一次筛选,易知每个基点必须要是正数,否则,我可以弱全都是负数的话,我可以去最大的负数,即为所要的解。将这些书以队列的形式存在positiveNum[](数据类型为dot)里,。
3.定义一个数组getableNum[],数据类型为dot,该数组用于存储可以延拓的点,但值一定是正数。
4.定义一个数组validNegativeDot[],数据类型为dot,该数组用于存储值为负数,但该店周围有比它该负数更大的正数。
5.定义一个数组path[],数据类型为dot,该数组用于记录连通图的路径。
6.算法,
a.初始化,先从positiveNum[]中取出一个基点,添加入path[]。
b.搜索该基点附近四个方位(上下左右)可以到达的点,其中值为正则存入getableNum[]里面,为负则存入validNegativeDot[]里面。
c.判定validNegativeDot[]里面的负数点是否是有效的,若有效,则将该数组周围最小的整数点,存入getableNum[]里面,并且该负数点添加入path[],然后更新validNegativeDot[]数组。
d.用广度优先搜索,将getableNum[]里面的点作为二次基点,重复a,b步骤。
e.直到getableNum[]和validNegativeDot[]里面没有任何点。计算此时path[]里面所有值得加和与maxSum比较大小,更新maxSum。然后再取出positiveNum[]的一个点,重复上述步骤。
f.直至positiveNum[]里面也没有值,算法宣布结束,此时的maxSum所要求的连通性最大子数组。
关于输入
这次作业还有一个很蛋疼的地方就是他的输入,因为老师要求,如果输入文件的参数有错误, 这个程序应该能正常退出, 并显示相应的错误信息, 任何输入错误都不能导致你的程序崩溃。本身C语言读字符串就蛋疼,再加上该要求输入就变得异乎寻常的蛋疼。最终统计,输入大概写了一个多小时,约100行。
代码:
1 for (i=1;i<argc-1;i++) 2 { 3 if (!strcmp(argv[i],"/v")) 4 isV = 1; 5 else if (!strcmp(argv[i],"/h")) 6 isH = 1; 7 else if (!strcmp(argv[i],"/a")) 8 isA = 1; 9 else{ 10 printf("command input error\n"); 11 return 0; 12 } 13 } 14 15 //File input 16 if((in = fopen(argv[argc-1], "r")) == NULL){ 17 printf("file open failed\n"); 18 return 0; 19 } 20 //row and line input 21 if(fgets(read, 256, in) == NULL){ 22 printf("ERROR: file input error\n"); 23 return 0; 24 } 25 line = convertToNum(read); 26 if(fgets(read, 256, in) == NULL){ 27 printf("ERROR: file input error\n"); 28 return 0; 29 } 30 row = convertToNum(read); 31 32 //Main array input 33 for (i=0;i<line;i++) 34 { 35 36 //getline 37 if(fgets(read, 256, in) == NULL){ 38 printf("ERROR: file input error\n"); 39 return 0; 40 } 41 42 length = strlen(read); 43 temp =0; 44 flag=0; 45 for(j=0;j<length;j++) 46 { 47 if(read[j]<='9'&&read[j]>='0'&& flag==0) 48 input[i][temp] = input[i][temp]*10+read[j]-'0'; 49 50 else if(read[j]<='9'&&read[j]>='0'&& flag==1) 51 { 52 input[i][temp] = -input[i][temp]; 53 input[i][temp] = -(input[i][temp]*10+read[j]-'0'); 54 55 } 56 else if(read[j] == ','||read[j]==',') 57 { 58 temp++; 59 flag=0; 60 } 61 else if(read[j]=='-') 62 flag=1; 63 } 64 if(temp<row-1) 65 { 66 printf("ERROR: file input error\n"); 67 return 0; 68 } 69 } 70 //closefile 71 fclose(in); 72 73 74 75 for (i=0;i<line;i++) 76 { 77 for(j=0;j<row;j++) 78 printf("%d ",input[i][j]); 79 printf("\n"); 80 } 81 82 switch (choose(isV,isH,isA)) 83 { 84 case 1 : 85 maxSum_1();return 1; 86 case 2 : 87 maxSum_2();return 1; 88 case 3: 89 maxSum_3();return 1; 90 default: 91 printf("ERROR:command input error"); 92 return 0; 93 } 94 95 96 //input 97 98 } 99 int convertToNum(char charArr[]) 100 { 101 int result=0; 102 int length,i; 103 length = strlen(charArr); 104 105 for(i=0;i<length-1;i++) 106 { 107 if(charArr[i]<='9'&&charArr[i]>='0') 108 result = result*10+charArr[i]-'0'; 109 else if(charArr[i] == ',') 110 return result; 111 } 112 return -1; 113 }
关于除第三次作业以外的作业
这个简单写写,因为算法都基本一样。
特别点的地方是,我才用了分模块的方式,因为根据我的考虑我有了/v和/h和不加有一点区别,所以我才用了3个函数
其中,什么参数都不加的由maxSum_1函数完成,至少有/v和/h中一个但不含/a由maxSum_2函数完成,有/a由maxSum_3完成,但是maxSum_3现在还未实现。
maxSum_2具体代码如下:
1 int max,maxend; 2 int ult,super,tmpsum; 3 int i,j,k,m; 4 ult = input[0][0]; 5 for(i = 0; i < line; i++){ 6 for(j = i; j < (isV ? line+i : line); j++){ 7 super = input[0][0]; 8 for(m = 0; m < (isH ? row : 1); m++){ 9 max = sum(line, row, i, j, m); 10 maxend = max; 11 for(k = m+1; k < (isH ? row+m : row); k++){ 12 tmpsum = sum(line, row, i, j, k); 13 maxend = maxend+tmpsum > tmpsum ? maxend+tmpsum : tmpsum; 14 max = max > maxend ? max : maxend; 15 } 16 super = max > super ? max : super; 17 } 18 ult = super > ult ? super : ult; 19 } 20 } 21 printf("%d\n", ult);
测试结果
测试用例:
测试结果:
单元测试和代码覆盖率:
这个还真不知道是个什么东西,希望老师或助教能够解释下。。。
项目时间
Personal Software Process Stages | 时间百分比(%) | 实际花费的时间 (分钟) | 原来估计的时间 (分钟) | |
Planning | 计划 |
|
|
|
Estimate | 估计这个任务需要多少时间,把工作细化并大致排序 | 2 | 20 min | 10 min |
Development | 开发 |
|
|
|
Analysis | 需求分析 (包括学习新技术) | 1 | 10 min | 20 min |
Design Spec | 生成设计文档 | 0 | 0 min | 0 min |
Design Review | 设计复审 (和同事审核设计文档) | 0 | 0 min | 0 min |
Coding Standard | 代码规范 (制定合适的规范) | 3 | 30 min | 20 min |
Design | 具体设计 | 11 | 100 min | 60 min |
Coding | 具体编码 | 32 | 320 min | 200 min |
Code Review | 代码复审 | 22 | 200 min | 150 min |
· Test | 测试(自我测试,修改代码,提交修改) |
| 150 min | 120 min |
Reporting | 总结报告 |
|
|
|
· Test Report | 测试报告 | 13 | 120 min | 100 min |
· Size Measurement | 计算工作量 | 1 | 10 min | 10 min |
· Postmortem & Improvement Plan | 事后总结, 并提出改进 | 1 | 10 min | 10 min |
Total | 总计 | 100% | 1000min | 700min |