您的位置:首页 > 其它

homework-02

2013-10-01 12:48 141 查看
这是我第二次写博客,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++在水平方向上扩大,通过这种方法成功降低了复杂度。具体的代码如下,有注释,大家应该都可以看得很明白:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <assert.h>
#include<stdlib.h>
using namespace std;

const int MAX = 10000;

int num[MAX][MAX],sum[MAX][MAX];

/*最大子数组之和*/
int MaxSubSum(int arr[],int nLen)
{
assert(num && nLen > 0);
int nMaxSum = arr[0];
int nCurSum = arr[0];
for (int i = 1;i < nLen;i++)
{
if (nCurSum < 0)
{
nCurSum = arr[i];
}
else
{
nCurSum += arr[i];
}
nMaxSum = max(nCurSum,nMaxSum);
}
return nMaxSum;
}
/*首尾相连最大子数组之和*/

int MaxSubSum_h(int arr[],int nLen)
{
assert(num && nLen > 0);
int nMaxSum = arr[0];
int nCurSum = arr[0];
for (int i = 1;i < nLen;i++)
{
if (nCurSum < 0)
{
nCurSum = arr[i];
}
else
{
nCurSum += arr[i];
}
nMaxSum = max(nCurSum,nMaxSum);
}
for (int i = 0;i < nLen;i++)
{
if (nCurSum < 0)
{
nCurSum = arr[i];
}
else
{
nCurSum += arr[i];
}
nMaxSum = max(nCurSum,nMaxSum);
}
return nMaxSum;
}
/*把原矩阵第i行和第j行之间元素进行压缩,形成一个一维数组*/
void InitSumArr(int nXLen,int nYLen)
{
assert(num && *num && sum && *sum);
assert(nXLen > 0 && nYLen > 0);
for (int i = 0;i < nXLen;i++)//横坐标
{
for (int j = 0;j < nYLen;j++)//纵坐标
{
sum[i][j] = 0;
for (int t = 0;t <= i;t++)
{
sum[i][j] += num[t][j];
}
}
}
}
/*枚举二维数组,压缩成一维数组,求解最大子数组和*/
int MaxSubMatrixSum(int nXLen,int nYLen)
{
assert(num && *num && sum && *sum);
assert(nXLen > 0 && nYLen > 0);
int nMaxSum = -0x3f3f3f3f;
int nCurSum = -0x3f3f3f3f;
int temp[MAX];
for (int i = 0;i < nXLen;i++)
{
for (int j = i;j < nXLen;j++)
{
if (i == 0)
{
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[j][t];
}
nCurSum = MaxSubSum(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
else
{
//计算每列元素和,并求最大子数组之和
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[j][t] - sum[i - 1][t];
}
nCurSum = MaxSubSum(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
}
}
return nMaxSum;
}

int main()
{
freopen("input.txt","r",stdin);
int nXLen = 0;
int nYLen = 0;
char c;

cin>>nXLen>>c>>nYLen>>c;

for (int i = 0;i < nXLen;i++)
for (int j = 0;j < nYLen;j++){
cin>>num[i][j];
if(j!=nYLen-1)   cin >> c;
}

InitSumArr(nXLen,nYLen);
cout<<MaxSubMatrixSum(nXLen,nYLen)<<endl;
system("pause");
return 0;
}


接下来是 水平垂直方向连接的问题,其实就是第一个问题的扩展,最重要的思路就是扩大空间,在水平或垂直方向上再补一个矩阵,同时保证j-i分别小于长宽,从而实现了连接,时间复杂度也没有上升,具体这部分的代码如下:(其他代码与第一个问题相同)

_v

int MaxSubMatrixSum_v(int nXLen,int nYLen)
{
assert(num && *num && sum && *sum);
assert(nXLen > 0 && nYLen > 0);
int nMaxSum = -0x3f3f3f3f;
int nCurSum = -0x3f3f3f3f;
int temp[MAX];
for (int i = 0;i < nXLen;i++)
{
for (int j = i;(j - i) < nXLen;j++)
{
if (i == 0)
{
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[j % nXLen][t];
}
nCurSum = MaxSubSum(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
else
{
//计算每列元素和,并求最大子数组之和
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[(j % nXLen)][t] - sum[i][t] + sum[nXLen - 1][t];
}
nCurSum = MaxSubSum(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
}
}
return nMaxSum;
}


_h(具体区别见MaxSubSum_h这个函数,有注释,实际思路是一样的)

int MaxSubMatrixSum_h(int nXLen,int nYLen)
{
assert(num && *num && sum && *sum);
assert(nXLen > 0 && nYLen > 0);
int nMaxSum = -0x3f3f3f3f;
//int Max = -0x3f3f3f3f;
int nCurSum = -0x3f3f3f3f;
int temp[MAX];
for (int i = 0;i < nXLen;i++)
{
for (int j = i;j < nXLen;j++)
{
if (i == 0)
{
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[j][t];
}
nCurSum = MaxSubSum_h(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
else
{
//计算每列元素和,并求最大子数组之和
for (int t = 0;t < nYLen;t++)
{
temp[t] = sum[j][t] - sum[i - 1][t];
}
nCurSum = MaxSubSum_h(temp,nYLen);
nMaxSum = max(nCurSum,nMaxSum);
}
}
//Max = max(nCurSum,Max);
}
return nMaxSum;


这就是作业的基本思路,接下来我回答一下老师这次提到的问题。

1、这次我是通过把相似但不同的问题单独模块化的方法来设计,这样具体的问题只要提取相应的模块即可,个人感觉比较稳定,当然没有很多很大的数据的考验。

2、单元测试/代码覆盖率这个内容我还是很生疏,这次我没有涉及,我是用dev c++编译的,以后我会补上这个内容。

3、第三个问题的填表情况如下:

Personal Software Process Stages

时间百分比(%)

实际花费的时间 (分钟)

原来估计的时间 (分钟)

Planning

计划

· Estimate

· 估计这个任务需要多少时间,把工作细化并大致排序

15%1h30mins
Development

开发

· Analysis

· 需求分析 (包括学习新技术)

10%50mins30mins
· Design Spec

· 生成设计文档

· Design Review

· 设计复审 (和同事审核设计文档)

· Coding Standard

· 代码规范 (制定合适的规范)

· Design

· 具体设计

30%2h30mins2h
· Coding

· 具体编码

20%1h30mins2h
· Code Review

· 代码复审

5%30mins10mins
· Test

· 测试(自我测试,修改代码,提交修改)

20%1h30mins1h
Reporting

总结报告

Test Report

测试报告

Size Measurement

计算工作量

Postmortem & Improvement Plan

事后总结, 并提出改进

Total总计100%总用时 8h总估计的用时 6h
总结,这次实践,首先对我来说非常具有挑战性,是个很好的机会,既真实发现了自己的不足,也锻炼了能力;其次,我学会了把一个复杂的问题分解成几个小问题,循序渐进,我也理解了老师这次出题的良苦用心,还有,通过填写表格,我深刻体会到了科学开发的重要性,正确的开发方法可以使我们提高效率,缩短时间,我在这方面还需要学习的很多,最后,通过这次作业,激发了我学习算法和优化的热情。

大致就这些,最后希望老师可以给我们讲解一下联通的问题,拓展我们的思路!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: