题意:
给你一个n * m (3 ≤ n, m ≤ 500)的矩阵。定义了一种螺旋矩阵。矩阵的边长为>=3的奇数。矩阵的值为矩阵的螺旋线上格子的权值和。螺旋线的定义为。从矩阵的左上角开始。依次按左,下,右,上的方向前进。转向的条件是当前格子的当前方向的下下个格子被走过了或到了矩阵的边界。结束的条件是不能再前进了。现在告诉你权值矩阵。要你找出子矩阵的最大权值。
思路:
为了减少频繁的求和操作我们预处理出rsum[i][j],第i行的前j项和。csum[j][i]。第j列的前i项和。通过观察会发现n=7比n=3.多出的部分和n=9比n=5多出的部分都是外围的不到一圈加一点。所以n=3,7,11,15的可以一圈一圈的加。n=5,9,13的和也可以一圈一圈的加。所以我们只需要枚举子矩阵的左上角和长度就可以算出最大权值了。最大时间复杂度为(500*500*250).这是最坏的估计。实际比这好的多。
详细见代码:
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const double PI=acos(-1.0);
const int maxn=100010;
int rsum[510][510],csum[510][510],val[510][510];
int main()
{
int n,m,i,j,ans,sum,x1,y1,x2,y2;
while(~scanf("%d%d",&n,&m))
{
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&val[i][j]);
for(i=1;i<=n;i++)
{
rsum[i][0]=0;
for(j=1;j<=m;j++)
rsum[i][j]=rsum[i][j-1]+val[i][j];
}
for(j=1;j<=m;j++)
{
csum[j][0]=0;
for(i=1;i<=n;i++)
csum[j][i]=csum[j][i-1]+val[i][j];
}
ans=-INF;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
x1=i,y1=j;
x2=x1+2,y2=y1+2;
if(x2<=n&&y2<=m)//3,7,11,15....
{
sum=rsum[x1][y2]-rsum[x1][y1-1]+csum[y2][x2]-csum[y2][x1]+rsum[x2][y2-1]-rsum[x2][y1-1];
ans=max(ans,sum);
while(x1-2>=1&&y1-2>=1&&x2+2<=n&&y2+2<=m)
{
x1-=2,y1-=2,x2+=2,y2+=2;
sum+=rsum[x1][y2]-rsum[x1][y1-1]+csum[y2][x2]-csum[y2][x1]+rsum[x2][y2-1]-rsum[x2][y1];
sum+=csum[y1][x2]-csum[y1][x1+1]+val[x1+2][y1+1];
ans=max(ans,sum);
}
}
x1=i,y1=j;
x2=x1+4,y2=y1+4;
if(x2<=n&&y2<=m)//5,9,13,17.....
{
sum=rsum[x1][y2]-rsum[x1][y1-1]+csum[y2][x2]-csum[y2][x1]+rsum[x2][y2-1]-rsum[x2][y1];
sum+=csum[y1][x2]-csum[y1][x1+1]+val[x1+2][y1+1]+val[x1+2][y1+2];
ans=max(ans,sum);
while(x1-2>=1&&y1-2>=1&&x2+2<=n&&y2+2<=m)
{
x1-=2,y1-=2,x2+=2,y2+=2;
sum+=rsum[x1][y2]-rsum[x1][y1-1]+csum[y2][x2]-csum[y2][x1]+rsum[x2][y2-1]-rsum[x2][y1];
sum+=csum[y1][x2]-csum[y1][x1+1]+val[x1+2][y1+1];
ans=max(ans,sum);
}
}
}
printf("%d\n",ans);
}
return 0;
}