poj 1050 To the Max(最大子矩阵和)

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">题意:给出一个N^2的矩阵,求最大子矩阵和。</span>

纯暴力应该是N^6,枚举从(i,j)到(p,q)的所有情况,把之间所有点相加计算总和,这样会导致很多数据进行重复的计算,复杂度太高,直接TLE,后来进行优化,先对数据做了一些预处理,记录点(1,1)到(i,j)的子矩阵和,然后枚举N^2个点,粗略估计复杂度为(n^4)/2,5kw,交上去63ms居然过了!继续思考了一下,可以转化为最大连续子序列的和的二维问题,这样的话复杂度只有N^3,16ms过。


①dp(16ms)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=105;
int n;
int sum[maxn][maxn];//sum[i][j]第j列前i行所有数的和

void init(){
	memset(sum,0,sizeof(sum));
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
#endif
	while(~scanf("%d",&n)){
		init();
		int x;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				scanf("%d",&x);
				sum[i][j]+=sum[i-1][j]+x;
			}
		}
		int res=-INF;
		for(int i=1;i<=n;i++){
			for(int j=i;j<=n;j++){
				int maximum=-INF,tmp=0;
				for(int k=1;k<=n;k++){
					tmp+=sum[j][k]-sum[i-1][k];
					if(tmp>maximum)
						maximum=tmp;
					if(tmp<0){
						tmp=0;
					}
				}
				if(maximum>res) res=maximum;
			}
		}
		printf("%d\n",res);
	}
	return 0;
}



②暴力(63ms)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=105;
int n;
int a[maxn][maxn];//a[i][j]表示第i行前j个点的和
int sum[maxn][maxn];//sum[i][j]表示由点(1,1)和点(i,j)形成的子矩阵和

void init(){
	memset(sum,0,sizeof(sum));
	memset(dp,0,sizeof(dp));
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
#endif
	while(~scanf("%d",&n)){
		init();
		int x;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				scanf("%d",&x);
				a[i][j]=a[i][j-1]+x;
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				for(int p=1;p<=i;p++){
					sum[i][j]+=a[p][j];
				}
			}
		}
		int res=-INF;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				for(int p=i;p<=n;p++){
					for(int q=j;q<=n;q++){
						int tmp=sum[p][q]-sum[p][j-1]-sum[i-1][q]+sum[i-1][j-1];
						if(tmp>res) res=tmp;
					}
				}
			}
		}
		printf("%d\n",res);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值