您的位置:首页 > 其它

最大子矩阵和

2016-02-13 13:49 169 查看
问:给定一个N*M的矩阵,其子矩阵有N*M*N*M个子矩阵,将子矩阵中的每个元素求和,求和最大的子矩阵。

我们可以枚举每个子矩阵,时间复杂度为0(N*M*N*M),代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=105;
int mat[MAXN][MAXN];
int sum[MAXN][MAXN];
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&mat[i][j]);

sum[1][1]=mat[1][1];
for(int i=2;i<=n;i++)
sum[1][i]=sum[1][i-1]+mat[1][i];
for(int i=2;i<=n;i++)
sum[i][1]=sum[i-1][1]+mat[i][1];

for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++)
{
sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+mat[i][j];//sum[i][j]表示左上角为mat[1][1],右下角为mat[i][j]所表示的矩阵之和
}

int res=-10000000;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int x=i;x<=n;x++)
for(int y=j;y<=n;y++)
{
int total=sum[x][y]-sum[x][j-1]-sum[i-1][y]+sum[i-1][j-1];
if(total>res)
res=total;
}

printf("%d\n",res);
}
return 0;
}


不过我们可以优化到o(N2*M)我们之前遇到过一个一维数组中最大子段和的问题。其状态转移方程为 if(b[i-1]>0) b[i]=b[i-1]+a[i] else b[i]=a[i],

其时间复杂度为0(N),代码如下:

int MaxSubSegSum(int num[])
{
int b[MAXN],maxn;
maxn=b[0]=num[0];
for(int i=1;i<m;i++)
{
if(b[i-1]>0)    b[i]=b[i-1]+num[i];
else    b[i]=num[i];
maxn=max(maxn,b[i]);
}
return maxn;
}


我们可以这样想:我们任意取第i行到第j行列全包含的子矩阵。我们将每行求和,转化为求最大子段和问题。我们就可以在O(M)的时间内枚举M*(M+1)/2个子矩阵,而这样的列全包含矩阵有

N*(N+1)/2 个。这样我们就可以在O(N*N*M)的时间内求得,这样大大降低了时间复杂度。

完整代码如下:

#include"cstdio"
#include"cstring"
#include"algorithm"
using namespace std;
const int MAXN=1005;
int n,m;
int matrix[MAXN][MAXN];
int l,r,up,down;
int ll,rr;
int lll,rrr;
int MaxSubSegSum(int num[])
{
int b[MAXN],maxn;
maxn=b[0]=num[0];
l=r=0;
for(int i=1;i<m;i++)
{
if(b[i-1]>0)
{
b[i]=b[i-1]+num[i];
r=i;
}
else
{
b[i]=num[i];
r=i;
l=i;
}
if(maxn<b[i])
{
maxn=b[i];
ll=l;
rr=r;
}
}
return maxn;
}
int total[MAXN][MAXN];
int MaxSubMat()
{
for(int j=0;j<m;j++)    total[0][j]=matrix[0][j];
for(int i=1;i<n;i++)
for(int j=0;j<m;j++)
{
total[i][j]=matrix[i][j];
total[i][j]+=total[i-1][j];
}
int maxn=-0x3fffffff;
int temp[MAXN];
for(int i=0;i<n;i++)
{
for(int j=i;j<n;j++)
{
for(int z=0;z<m;z++)
{
if(i==0)    temp[z]=total[j][z];
else    temp[z]=total[j][z]-total[i-1][z];
}
if(MaxSubSegSum(temp)>maxn)
{
maxn=MaxSubSegSum(temp);
up=i;
down=j;
lll=ll;
rrr=rr;
}
}
}
return maxn;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)    scanf("%d",&matrix[i][j]);
int ans=MaxSubMat();
printf(" 最大子矩阵为:\n");
for(int i=up;i<=down;i++)
{
for(int j=lll;j<=rrr;j++)    printf("%d ",matrix[i][j]);
printf("\n");
}
printf("其和为:%d\n",ans);
return 0;
}
/*
3 3
-1 3 -1
2 -1 3
-3 1 2

3 -1
-1 3
1 2
7
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: