<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;
}