题目链接: http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3352&konwledgeId=40
解题思路: 首先,考虑一维的情况。a1,a2,a3,....an的最大子序列和。我们维护一个(最大前缀和),当这个前缀和小于0的时候,就替换为当前值,那么最大值一定在这些前缀和中。
然后对于二维的情况,我们枚举可能的起始列标,这样就是一维的最大子序列和的问题了。例如,当我们选定第一列和第三列后,把每一行第一列到第三列的数加在一起,那么就是一个一维的问题了。对于给定区间的和,我们可以通过前缀和O(1)计算,sum[i,j]=sum[0,j]-sum[0,i-1]。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int MAXN=100005; 6 const LL MON7 = 1e9+7; 7 int a[105][105]; 8 int sum[105][105]; 9 int n,m; 10 11 void solve() 12 { 13 int ans=-2000; 14 for (int p=1;p<=m;++p) 15 { 16 for (int q=p;q<=m;q++) 17 { 18 int tmp=-2000; 19 for (int i=1;i<=n;++i) 20 { 21 if (tmp<0) tmp=sum[i][q]-sum[i][p-1]; 22 else tmp+=sum[i][q]-sum[i][p-1]; 23 ans=max(ans,tmp); 24 } 25 } 26 } 27 printf("%d ",ans); 28 } 29 30 int main() 31 { 32 #ifndef ONLINE_JUDGE 33 freopen("test.txt","r",stdin); 34 #endif // ONLINE_JUDGE 35 int Case; 36 scanf("%d",&Case); 37 while (Case--) 38 { 39 scanf("%d%d",&n,&m); 40 memset(sum,0,sizeof(sum)); 41 for (int i=1;i<=n;++i) 42 { 43 for (int j=1;j<=m;++j) 44 { 45 scanf("%d",&a[i][j]); 46 sum[i][j]=sum[i][j-1] + a[i][j]; 47 } 48 } 49 solve(); 50 } 51 return 0; 52 }