题目大意:
就是现在给出一个n*n的矩阵中的所有的值,求其中取出一块区域的最大和。
大致思路:
首先考虑一维上的相似的一个问题:
对于数列a[ n ]找出连续的子串使得和最大,那么用 dp[ i ] 表示以第 i 个作为结尾的字串最大和, 那么 dp[ i ] = max(dp[ i - 1 ] + a[ i ], a[ i ])
那么一个二维的情况,我们讨论以第 i 行到第 j 行的情况,将其作为一个整体,预处理每列的前n行的和就可以很快地得到每列第 i 行到第 j 行的和,作为一个整体就类似于上面以为的步骤了,预处理复杂度为O(n*n),枚举 i 和 j ,dp算对应情形下的最大子列和,时间复杂度为O(n^3)
总体时间复杂度为O(n^3)可以接受
代码如下:
Result : Accepted Memory : 376 KB Time : 0 ms
/*
* Author: Gatevin
* Created Time: 2014/8/15 17:13:49
* File Name: haha.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
int n;
int a[101][101];
int sum[101][101];
int dp[101][101];
int main()
{
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &a[i][j]);
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
sum[i][j] = sum[i][j - 1] + a[i][j];
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
int tmp = 0;
for(int k = 1; k <= n; k++)
{
tmp += sum[k][j] - sum[k][i - 1];
dp[i][j] = max(dp[i][j], tmp);
if(tmp < 0) tmp = 0;
}
}
}
int answer = dp[1][1];
for(int i = 1; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
answer = max(answer, dp[i][j]);
}
}
printf("%d\n", answer);
}
return 0;
}