To the Max-POJ1050-二维区间前缀和

版权声明:未经博主同意,不可转载 https://blog.csdn.net/pythonbanana/article/details/88371216

题意:
给你一个方阵,求其子矩阵和的最大值。
思路:
如果朴素枚举的话,复杂度O(n4),如果使用前缀和,可以降一维,所以O(n3);。
枚举就是枚举当前行i,然后枚举后面的行j(j>=i),然后再枚举列k(1,n).但是可能会有问题,因为这样枚举,中间的子矩阵看似没有枚举到。按照这样的枚举方式,如果最大子矩阵在中间,那么前面的列的元素和肯定<0,所以我们将前面<0的部分删去,就可以枚举到中间的子矩阵了。
还有算法朴素枚举的话,会有很多计算结果没有被利用起来。其实可以像前缀和一样,由当前状态不断叠加,得到后面的状态。
所以有些时候,不要被表面现象迷惑。不要想当然的因为之前的枚举方式,没有枚举到中间的子矩阵,就放弃这种方法。而应该假设如果中间的子矩阵是最优解,那么会怎么样?(前面部分小于0,我们把小于0的更新为0即可)。
还有一点就是,我们要充分利用计算结果,不能浪费计算出来的结果,一步一步叠加得到后面的状态,就充分利用到了之前的计算结果。这一点在Malache算法中体现得淋漓尽致。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 1e2;
int n = 0,m = 0; 
int a[maxn+10][maxn+10];//a[i][j]表示前i行,第j列的所有元素和 
/*
如果朴素枚举的话,复杂度O(n4),如果使用前缀和,可以降一维,所以O(n3); 
*/
int main(){
	//std::ios::sync_with_stdio(false);
	while(~scanf("%d",&n)){
		memset(a,0,sizeof(a));
		per(i,1,n){
			per(j,1,n){
				int t = 0;
				scanf("%d",&t);
				a[i][j] = a[i-1][j] + t;
			}
		}
		int maxv = a[1][1];
		per(i,1,n){
			per(j,i,n){
				int sum = 0;
				per(k,1,n){
					sum += (a[j][k] - a[i-1][k]);
					if(sum < 0){//及时纠正,这样如果中间的和会更大就会枚举到他 
						sum = 0;
					}
					if(sum > maxv){
						maxv = sum;
					}
				}
			}
		}
		printf("%d\n",maxv);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pythonbanana/article/details/88371216