homework-02

GitHub挂了...我会在其恢复的时候上传我的代码的...其实代码就在blog里面...

已解决...是我自己的问题...之前没有pull一下...结果就上传不上去...

一. 程序的架构和思路:

其实吧...这个第二次作业是在第一次作业上的延伸,于是算法应该和第一次的相似,或者说是将二维转化为一维,然后再做...

但还是从朴素算法开始想吧...

最最朴素的算法,就是一个六重循环,枚举矩阵的左上和右下两个点的x、y坐标,然后计算这之中的值的和即可。

#include<iostream>
#include<cstdio>
#include<time.h>
using namespace std;
int a[1010][1010];
int main()
{
    freopen("input.txt","r",stdin);
    clock_t start,finish;
    start = clock();
    double totaltime;
    int m,n;
    int i,j,p,q,k,l,ans,temp = 0;
    scanf("%d,",&m);
    scanf("%d,",&n);
    for (i = 0;i < m;i++)
    for (j = 0;j < n;j++) scanf("%d,",&a[i][j]);
    ans = a[0][0];
    for (i = 0;i < m;i++)
    for (j = 0;j < n;j++)
    for (p = i;p < m;p++)
    for (q = j;q < n;q++)
    {
        temp = 0;
        for (k = i;k <= p;k++)
        for (l = j;l <= q;l++) temp = temp + a[k][l];
        if (temp > ans) ans = temp;
    }
    printf("%d\n",ans);
    finish = clock();
    totaltime = finish - start;
    printf("%lf\n",totaltime);
    fclose(stdin);
    return 0;
}
View Code

所以该继续优化了...

由代码观之,朴素算法时间复杂度为O(n^6)...这个...太大了有点...

但是,其空间复杂度为1,根据动态规划的基本思想——空间换时间来优化算法。

先从计算两点间矩阵的和下手。

我们可以如此优化:记b[i][j]为左上角到(i,j)的矩阵的和。

因此,(i,j)到(m,n)的矩阵的和就可以表示为:b[m][n]-b[m][j-1]-b[i-1][n]+b[i-1][j-1]。

#include<iostream>
#include<cstdio>
#include<time.h> 
using namespace std;
int a[1010][1010];
int b[1010][1010];
int main()
{
    freopen("input.txt","r",stdin);
    clock_t start,finish;
    start = clock();
    double totaltime;
    int m,n;
    int i,j,p,q,ans,temp = 0;
    scanf("%d,",&m);
    scanf("%d,",&n);
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++) scanf("%d,",&a[i][j]);
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++)
    {
        temp = 0;
        for (p = 1;p <= i;p++)
        for (q = 1;q <= j;q++) temp = temp + a[p][q];
        b[i][j] = temp;
    }
    ans = a[1][1];
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++)
    for (p = i;p <= m;p++)
    for (q = j;q <= n;q++)
    {
        temp = b[p][q] - b[p][j - 1] - b[i - 1][q] + b[i - 1][j - 1];
        if (temp > ans) ans = temp;
    }
    printf("%d\n",ans);
    finish = clock();
    totaltime = finish - start;
    printf("%lf\n",totaltime);
    fclose(stdin);
    return 0;
}
View Code

优化后,算法时间复杂度为O(n^4),空间复杂度为O(n^2)。

需要注意的是,这么做读入数据时要从1开始不要从0开始,因为会有i-1的情况,要保证其大于等于0。

貌似...O(n^4)还是有点大...

秉承空间换时间的基本方针,可以继续优化。

这次就需要基于第一次作业了。

扩大空间,我们用b[i][j][k]表示第k列的第i行到第j行的和,于是我们将其转化为了b[i][j][0],b[i][j][1],...,b[i][j][k]这样一个一维数列

于是就可以求其最大子序列和了。

#include<iostream>
#include<cstdio>
#include<time.h>
#include<cstring>
using namespace std;
int a[1010][1010];
int b[101][101][101];
int max(int x,int y)
{
    if (x > y) return x;
    else return y;
}
int main()
{
    freopen("input.txt","r",stdin);
    clock_t start,finish;
    start = clock();
    double totaltime;
    int m,n;
    int i,j,k,ans,temp = 0;
    scanf("%d,",&m);
    scanf("%d,",&n);
    for (i = 0;i < m;i++)
    for (j = 0;j < n;j++) scanf("%d,",&a[i][j]);
    ans = a[0][0];
    for (i = 0;i < m;i++)
    for (j = 0;j < n;j++) ans = max(ans,a[i][j]);
    memset(b,0,sizeof(b));
    for (k = 0;k < n;k++)
    {
        for (i = 0;i < m;i++)
        {
            temp = 0;
            for (j = i;j < m;j++)
            {
                temp = temp + a[j][k];
                b[i][j][k] = temp;
            }
        }
    }
    for (i = 0;i < m;i++)
    for (j = i;j < m;j++)
    {
        temp = 0;
        for (k = 0;k < n;k++)
        {
            temp = temp + b[i][j][k];
            if (temp > ans) ans = temp;
            else if (temp < 0) temp = 0;
        }
    }
    printf("%d\n",ans);
    finish = clock();
    totaltime = finish - start;
    printf("%lf\n",totaltime);
    fclose(stdin);
    return 0;
}
View Code

这样时间复杂度就优化到O(n^3)了,可以解决较大矩阵了,但是,空间复杂度同样到达了O(n^3),可能会爆内存。

根据第一次优化的方法,我们可以继续优化空间复杂度。

用b[i][k]-b[j-1][k]来表示b[i][j][k]。

#include<iostream>
#include<cstdio>
#include<time.h>
#include<cstring>
using namespace std;
int a[1010][1010];
int b[1010][1010];
int max(int x,int y)
{
    if (x > y) return x;
    else return y;
}
int main()
{
    freopen("input.txt","r",stdin);
    clock_t start,finish;
    start = clock();
    double totaltime;
    int m,n;
    int i,j,k,ans,temp = 0;
    scanf("%d,",&m);
    scanf("%d,",&n);
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++) scanf("%d,",&a[i][j]);
    ans = a[1][1];
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++) ans = max(ans,a[i][j]);
    memset(b,0,sizeof(b));
    for (j = 1;j <= n;j++)
    {
        temp = 0;
        for (i = 1;i <= m;i++)
        {
            temp = temp + a[i][j];
            b[i][j] = temp;
        }
    }
    for (i = 1;i <= m;i++)
    for (j = i;j <= m;j++)
    {
        temp = 0;
        for (k = 1;k <= n;k++)
        {
            temp = temp + b[j][k] - b[i - 1][k];
            if (temp > ans) ans = temp;
            else if (temp < 0) temp = 0;
        }
    }
    printf("%d\n",ans);
    finish = clock();
    totaltime = finish - start;
    printf("%lf\n",totaltime);
    fclose(stdin);
    return 0;
}
View Code

这样,时间复杂度不变,空间复杂度变为了O(n^2),但同第二个算法,读入数据时要从1开始不要从0开始。

先跳过不规则连通子图...

对于上下连通的情况,可以在正下方补一个相同的矩阵,这样在两个矩阵中可以实现上下连通的情况。

需要注意的是这样要求第j行减去第i行要小于等于矩阵的宽。

#include<iostream>
#include<cstdio>
#include<time.h>
#include<cstring>
using namespace std;
int a[1010][1010];
int b[1010][1010];
int max(int x,int y)
{
    if (x > y) return x;
    else return y;
}
int main()
{
    freopen("input.txt","r",stdin);
    clock_t start,finish;
    start = clock();
    double totaltime;
    int m,n;
    int i,j,k,ans,temp = 0;
    scanf("%d,",&m);
    scanf("%d,",&n);
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++)
    {
        scanf("%d,",&a[i][j]);
        a[i + m][j] = a[i][j];
    }
    ans = a[1][1];
    for (i = 1;i <= m;i++)
    for (j = 1;j <= n;j++) ans = max(ans,a[i][j]);
    memset(b,0,sizeof(b));
    for (j = 1;j <= n;j++)
    {
        temp = 0;
        for (i = 1;i <= m * 2;i++)
        {
            temp = temp + a[i][j];
            b[i][j] = temp;
        }
    }
    for (i = 1;i <= m;i++)
    for (j = i;j <= m;j++)
    {
        if ((j - i) <= m)
        {
            temp = 0;
            for (k = 1;k <= n;k++)
            {
                temp = temp + b[j][k] - b[i - 1][k];
                if (temp > ans) ans = temp;
                else if (temp < 0) temp = 0;
            }
        }
    }
    printf("%d\n",ans);
    finish = clock();
    totaltime = finish - start;
    printf("%lf\n",totaltime);
    fclose(stdin);
    return 0;
}
View Code

对于左右连通的情况,同样需要向右补一个相同的矩阵,然后并保证所选子矩阵的长不大于原矩阵即可。

但是,从左向右做记录的时候需要另开一个变量记录长度。

实在是懒得写了...索性把上下连通的代码的长宽对调,让其从上往下做,完美解决。

不规则的连通子图,想了想还是没有特别好的办法能够解决32*32的数据。

最朴素的算法就是枚举每个点的状态,用0和1表示。

然后dfs判断连通性并找最大子块,这样的时间复杂度是O(2^(m*n)),就是10*10可解,32*32不可解。

由此想到是否可用状态压缩动态规划做,但是似乎0、1两个状态不够,还需要表示上下连通等其他状态并且似乎转移的时候也有问题。

于是就要用0,1,...,k来表示状态,稍微算了一下时间复杂度,已经是个天文数字了...

于是这一问我实在是想不出什么好的算法了...

 二. 程序运行截图:

自上至下依次为第二至第五个算法的运行结果(第一个O(n^6)的实在是跑不出来了...数据是100*100的):

 

由此可见,速度的提升是极其明显的。

. 回答问题:

述在这么多相似的需求面前, 你怎么维护你的设计 (父类/子类/基类, UML, 设计模式,  或者其它方法) 让整个程序的架构不至于崩溃的?

答:我目前是把每个需求分开来写的...如果要合并的话,也许利用case语句能达到要求。

给出你做单元测试/代码覆盖率的最终覆盖率的报告, 用截屏显示你的代码覆盖率.

答:我写的程序是面向过程的...貌似没法做单元测试么?

你在这个作业中学到了什么?  有什么好的设计值得分享?  感想如何 (太容易 / 太难 / 太无趣)?

答:我尝试去学习状态压缩动态规划,但还是不会做那一问...值得分享的是关于多维问题,可以由简单推复杂,即由一维推多维。

说实话...那个不规则的最大子图那一问有点难...

 

Personal Software Process Stages

时间百分比(%)

实际花费的时间 (分钟)

原来估计的时间 (分钟)

Planning

计划

     

·         Estimate

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

 4.8%  30 30

Development

开发

     

·         Analysis

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

 9.6%  60  30

·         Design Spec

·         生成设计文档

 2.4%  15  10

·         Design Review

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

 0%  0  0

·         Coding Standard

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

 1.6%  10  10

·         Design

·         具体设计

 9.6%  60  80

·         Coding

·         具体编码

 38.4%  240  150

·         Code Review

·         代码复审

 19.2%  120  50

·         Test

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

 6.4%  40  60

Reporting

总结报告

     
  • Test Report
  • 测试报告
   3.2% 20  30
  • Size Measurement
  • 计算工作量
  • Postmortem & Improvement Plan
  • 事后总结, 并提出改进
  4.8% 30  30
         
Total 总计 100%

总用时

625

总估计的用时

470

posted @ 2013-10-01 09:11  yiming.zou  阅读(264)  评论(1编辑  收藏  举报