Homework-01

  话说好不容易选上这门课了,却也已经错过第一次课了。作业也是妥妥的迟了,趁着中秋赶紧补上,望老师见谅。

  参考书选择代码大全。

最大子数组和问题分析

一维情况

  首先想到的应该是O(n^2)的算法(一般不会想到n^3方的算法吧。。略蛋疼)。用sum[i]表示数组中1到i的和,并令sum[0]=0。f[i]表示以i结尾的最大子数组和。那么有f[i]=Max{sum[i]-sum[j]|0<=j<=i-1}。最终结果是ans=Max{f[i]|1<=i<=n}。这个算法显然是O(n^2)的。

  然后考虑对其进行优化。考虑到f[i]=Max{sum[i]-sum[j]|0<=j<=i-1}可以把只与i相关部分分离出来,变为f[i]=sum[i]-Min{sum[j]|0<=j<=i-1}。我们可以定义m[i]=Min{sum[j]|0<=j<=i},整个式子就变为f[i]=sum[i]-m[i-1]。只要sum和m都能很快求出,那么f也就能很快求出。显然sum可以O(n)的求出来,而m也可以在求sum的同时求出。所以sum和m的求解都是O(n)的。那么f的求解也就是O(n)的,在求f的同时更新最大值即可。

  这个问题还有很多别的O(n)的做法,而且基本都比上面的做法更简洁,但上面这种方法应该是最容易想到的。在实现上其实不需要数组,全部使用临时变量即可,因为每读一个数据就可以求出所有需要的sum、m、f,具体见程序。

二维情况

  见到高维的问题自然会想到将其转化为低维的问题。对于这个问题,只要先确定最大子块的上下界,就能将其转化为一维。上下界共有O(n^2)种可能,对每个上下界应用一维算法需要O(m)的时间,所以总共是O(n^2*m)的。实现时需要一个二维数组存储sum[i,j],表示(1,1)到(i,j)的和,其余都用临时变量即可。

代码

 1 #include <stdio.h>
 2 #define MAXN 100000000
 3 FILE *fin,*fout;
 4 int main(void)
 5 {
 6     fin=fopen("in.txt","r");
 7     fout=fopen("out.txt","w");
 8     int n,i,sum,m,ans,a,f;
 9     
10     fscanf(fin,"%d\n",&n);
11 
12     sum=0;
13     m=0;
14     ans=-MAXN;
15     
16     for(i=1;i<=n;i++)
17     {
18         fscanf(fin,",%d",&a);
19         sum+=a;
20         f=sum-m;
21         if(f>ans)ans=f;
22         if(sum<m)m=sum;
23     }
24     
25     fprintf(fout,"%d\n",ans);
26     return 0;
27 }
一维情况
 1 #include <stdio.h>
 2 #define MAXN 100000000
 3 FILE *fin,*fout;
 4 int sum[100][100];
 5 int main(void)
 6 {
 7     fin=fopen("in.txt","r");
 8     fout=fopen("out.txt","w");
 9     int n,m,i,j,k,a,ans,min,f;
10 
11     fscanf(fin,"%d,%d,",&n,&m);
12     for(i=1;i<=n;i++)
13         for(j=1;j<=m;j++)
14         {
15             fscanf(fin,"%d,",&a);
16             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a;
17         }
18     
19     ans=-MAXN;
20     for(i=1;i<=n;i++)
21         for(j=i;j<=n;j++)
22         {
23             min=0;
24             for(k=1;k<=m;k++)
25             {
26                 f=sum[j][k]-sum[i-1][k]-min;
27                 if(f>ans)
28                     ans=f;
29                 if(sum[j][k]-sum[i-1][k]<min)
30                     min=sum[j][k]-sum[i-1][k];
31             }
32         }
33 
34     fprintf(fout,"%d\n",ans);
35     return 0;
36 }
二维情况

测试结果

 由于时间比较紧,先借用一下forwil同学的数据。。

一维情况:

6,
5,6,-3,8,-9,2

输出结果 16

 

二维情况:

3,
6,
5,6,-3,8,-9,2
1,-12,20,0,-3,-5
-9,-7,-3,6,7,-1

输出结果 28

posted @ 2013-09-22 20:14  zjoe  阅读(215)  评论(0编辑  收藏  举报