题目:最大子矩阵
思路:
前缀和+扫描线(或者是dp?听说是dp?),复杂度O(n^3)。
枚举最大子矩阵的上下边界,然后把每一列的和加起来成为一个序列,注意这里要用前缀和优化。
嗯然后对于这个子序列再求前缀和,然后扫描线扫一遍,每次用自己减去前面的最小值更新最大的答案。
当然这个题目的数据朴素算法O(n^4)可过的。
一维问题:Subsequence
代码:
O(n^3)算法:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100
int n;
int a[maxn+5][maxn+5];
int sum[maxn+5][maxn+5]={0};
int b[maxn+5]={0};
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
sum[i][j]=sum[i-1][j]+a[i][j];
}
}
int ans=-(1<<30);
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
for(int k=1;k<=n;k++){
b[k]=sum[i][k]-sum[j-1][k]+b[k-1];
}
int w=0;
for(int k=1;k<=n;k++){
ans=max(ans,b[k]-b[w]);
if(b[k]<b[w]) w=k;
}
}
}
printf("%d",ans);
return 0;
}
O(n^4)算法:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100
int n;
int a[maxn+5][maxn+5];
int sum[maxn+5][maxn+5]={0};
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
}
}
int ans=-(1<<30);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=i;k<=n;k++){
for(int u=j;u<=n;u++){
ans=max(ans,sum[k][u]-sum[i-1][u]-sum[k][j-1]+sum[i-1][j-1]);
}
}
}
}
printf("%d",ans);
return 0;
}