homework-02
2013-10-01 12:48 adun_li 阅读(242) 评论(3) 编辑 收藏 举报这是我第二次写博客,homework two果真是很难,我听到了同学们的哀怨声,而我也是其中一个,或者说我是一个很菜的选手,这次作业,我一共完成了二维数组求最大子数组的和,水平和垂直方向的连接求和,至于联通的问题,只听到大牛在说什么dp,自己也有一些想法,但是实践起来复杂度很高,就放弃了,由衷的希望老师可以针对这个问题好好讲解一下。
言归正传,我来说说这次作业的思路,这次我的编写语言是c++,首先是二维数组求最大子数组的和的问题,参考作业一,可以想到把二维数组向一维的方向前进,最朴素的算法时间复杂度是O(n^6),不断优化,可以最终达到O(n^3),基本思路就是创建一个新的二维数组sum[i][t],其中每个元素代表从num[0][0]到num[i][j]所组成的矩阵中所有元素的和,这样在求任意一个矩阵就可以充分利用sum[j][t]-sum[i-1][t]这个式子,同时可以用t++在水平方向上扩大,通过这种方法成功降低了复杂度。具体的代码如下,有注释,大家应该都可以看得很明白:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <assert.h> 6 #include<stdlib.h> 7 using namespace std; 8 9 const int MAX = 10000; 10 11 int num[MAX][MAX],sum[MAX][MAX]; 12 13 /*最大子数组之和*/ 14 int MaxSubSum(int arr[],int nLen) 15 { 16 assert(num && nLen > 0); 17 int nMaxSum = arr[0]; 18 int nCurSum = arr[0]; 19 for (int i = 1;i < nLen;i++) 20 { 21 if (nCurSum < 0) 22 { 23 nCurSum = arr[i]; 24 } 25 else 26 { 27 nCurSum += arr[i]; 28 } 29 nMaxSum = max(nCurSum,nMaxSum); 30 } 31 return nMaxSum; 32 } 33 /*首尾相连最大子数组之和*/ 34 35 int MaxSubSum_h(int arr[],int nLen) 36 { 37 assert(num && nLen > 0); 38 int nMaxSum = arr[0]; 39 int nCurSum = arr[0]; 40 for (int i = 1;i < nLen;i++) 41 { 42 if (nCurSum < 0) 43 { 44 nCurSum = arr[i]; 45 } 46 else 47 { 48 nCurSum += arr[i]; 49 } 50 nMaxSum = max(nCurSum,nMaxSum); 51 } 52 for (int i = 0;i < nLen;i++) 53 { 54 if (nCurSum < 0) 55 { 56 nCurSum = arr[i]; 57 } 58 else 59 { 60 nCurSum += arr[i]; 61 } 62 nMaxSum = max(nCurSum,nMaxSum); 63 } 64 return nMaxSum; 65 } 66 /*把原矩阵第i行和第j行之间元素进行压缩,形成一个一维数组*/ 67 void InitSumArr(int nXLen,int nYLen) 68 { 69 assert(num && *num && sum && *sum); 70 assert(nXLen > 0 && nYLen > 0); 71 for (int i = 0;i < nXLen;i++)//横坐标 72 { 73 for (int j = 0;j < nYLen;j++)//纵坐标 74 { 75 sum[i][j] = 0; 76 for (int t = 0;t <= i;t++) 77 { 78 sum[i][j] += num[t][j]; 79 } 80 } 81 } 82 } 83 /*枚举二维数组,压缩成一维数组,求解最大子数组和*/ 84 int MaxSubMatrixSum(int nXLen,int nYLen) 85 { 86 assert(num && *num && sum && *sum); 87 assert(nXLen > 0 && nYLen > 0); 88 int nMaxSum = -0x3f3f3f3f; 89 int nCurSum = -0x3f3f3f3f; 90 int temp[MAX]; 91 for (int i = 0;i < nXLen;i++) 92 { 93 for (int j = i;j < nXLen;j++) 94 { 95 if (i == 0) 96 { 97 for (int t = 0;t < nYLen;t++) 98 { 99 temp[t] = sum[j][t]; 100 } 101 nCurSum = MaxSubSum(temp,nYLen); 102 nMaxSum = max(nCurSum,nMaxSum); 103 } 104 else 105 { 106 //计算每列元素和,并求最大子数组之和 107 for (int t = 0;t < nYLen;t++) 108 { 109 temp[t] = sum[j][t] - sum[i - 1][t]; 110 } 111 nCurSum = MaxSubSum(temp,nYLen); 112 nMaxSum = max(nCurSum,nMaxSum); 113 } 114 } 115 } 116 return nMaxSum; 117 } 118 119 int main() 120 { 121 freopen("input.txt","r",stdin); 122 int nXLen = 0; 123 int nYLen = 0; 124 char c; 125 126 cin>>nXLen>>c>>nYLen>>c; 127 128 for (int i = 0;i < nXLen;i++) 129 for (int j = 0;j < nYLen;j++){ 130 cin>>num[i][j]; 131 if(j!=nYLen-1) cin >> c; 132 } 133 134 InitSumArr(nXLen,nYLen); 135 cout<<MaxSubMatrixSum(nXLen,nYLen)<<endl; 136 system("pause"); 137 return 0; 138 }
接下来是 水平垂直方向连接的问题,其实就是第一个问题的扩展,最重要的思路就是扩大空间,在水平或垂直方向上再补一个矩阵,同时保证j-i分别小于长宽,从而实现了连接,时间复杂度也没有上升,具体这部分的代码如下:(其他代码与第一个问题相同)
_v
1 int MaxSubMatrixSum_v(int nXLen,int nYLen) 2 { 3 assert(num && *num && sum && *sum); 4 assert(nXLen > 0 && nYLen > 0); 5 int nMaxSum = -0x3f3f3f3f; 6 int nCurSum = -0x3f3f3f3f; 7 int temp[MAX]; 8 for (int i = 0;i < nXLen;i++) 9 { 10 for (int j = i;(j - i) < nXLen;j++) 11 { 12 if (i == 0) 13 { 14 for (int t = 0;t < nYLen;t++) 15 { 16 temp[t] = sum[j % nXLen][t]; 17 } 18 nCurSum = MaxSubSum(temp,nYLen); 19 nMaxSum = max(nCurSum,nMaxSum); 20 } 21 else 22 { 23 //计算每列元素和,并求最大子数组之和 24 for (int t = 0;t < nYLen;t++) 25 { 26 temp[t] = sum[(j % nXLen)][t] - sum[i][t] + sum[nXLen - 1][t]; 27 } 28 nCurSum = MaxSubSum(temp,nYLen); 29 nMaxSum = max(nCurSum,nMaxSum); 30 } 31 } 32 } 33 return nMaxSum; 34 }
_h(具体区别见MaxSubSum_h这个函数,有注释,实际思路是一样的)
1 int MaxSubMatrixSum_h(int nXLen,int nYLen) 2 { 3 assert(num && *num && sum && *sum); 4 assert(nXLen > 0 && nYLen > 0); 5 int nMaxSum = -0x3f3f3f3f; 6 //int Max = -0x3f3f3f3f; 7 int nCurSum = -0x3f3f3f3f; 8 int temp[MAX]; 9 for (int i = 0;i < nXLen;i++) 10 { 11 for (int j = i;j < nXLen;j++) 12 { 13 if (i == 0) 14 { 15 for (int t = 0;t < nYLen;t++) 16 { 17 temp[t] = sum[j][t]; 18 } 19 nCurSum = MaxSubSum_h(temp,nYLen); 20 nMaxSum = max(nCurSum,nMaxSum); 21 } 22 else 23 { 24 //计算每列元素和,并求最大子数组之和 25 for (int t = 0;t < nYLen;t++) 26 { 27 temp[t] = sum[j][t] - sum[i - 1][t]; 28 } 29 nCurSum = MaxSubSum_h(temp,nYLen); 30 nMaxSum = max(nCurSum,nMaxSum); 31 } 32 } 33 //Max = max(nCurSum,Max); 34 } 35 return nMaxSum; 36
这就是作业的基本思路,接下来我回答一下老师这次提到的问题。
1、这次我是通过把相似但不同的问题单独模块化的方法来设计,这样具体的问题只要提取相应的模块即可,个人感觉比较稳定,当然没有很多很大的数据的考验。
2、单元测试/代码覆盖率这个内容我还是很生疏,这次我没有涉及,我是用dev c++编译的,以后我会补上这个内容。
3、第三个问题的填表情况如下:
Personal Software Process Stages |
时间百分比(%) |
实际花费的时间 (分钟) |
原来估计的时间 (分钟) |
|
Planning |
计划 |
|||
· Estimate |
· 估计这个任务需要多少时间,把工作细化并大致排序 |
15% | 1h | 30mins |
Development |
开发 |
|||
· Analysis |
· 需求分析 (包括学习新技术) |
10% | 50mins | 30mins |
· Design Spec |
· 生成设计文档 |
|||
· Design Review |
· 设计复审 (和同事审核设计文档) |
|||
· Coding Standard |
· 代码规范 (制定合适的规范) |
|||
· Design |
· 具体设计 |
30% | 2h30mins | 2h |
· Coding |
· 具体编码 |
20% | 1h30mins | 2h |
· Code Review |
· 代码复审 |
5% | 30mins | 10mins |
· Test |
· 测试(自我测试,修改代码,提交修改) |
20% | 1h30mins | 1h |
Reporting |
总结报告 |
|||
|
|
|||
|
||||
Total | 总计 | 100% | 总用时 8h | 总估计的用时 6h |
总结,这次实践,首先对我来说非常具有挑战性,是个很好的机会,既真实发现了自己的不足,也锻炼了能力;其次,我学会了把一个复杂的问题分解成几个小问题,循序渐进,我也理解了老师这次出题的良苦用心,还有,通过填写表格,我深刻体会到了科学开发的重要性,正确的开发方法可以使我们提高效率,缩短时间,我在这方面还需要学习的很多,最后,通过这次作业,激发了我学习算法和优化的热情。
大致就这些,最后希望老师可以给我们讲解一下联通的问题,拓展我们的思路!