http://10.7.18.82/JudgeOnline/showproblem?problem_id=1709
最优子矩阵
Time Limit: 5000MS | Memory Limit: 65536K | |||
Total Submissions: 177 | Accepted: 50 |
Description
已知一个矩阵行数为n,列数为m,其中 ( 0 < n,m < = 1000 ),从这个矩阵中找出一个子矩阵( 行数为x,列数为y,0 < x , y <= 100 ),每个子矩阵的所有元素的和为sum,求所有sum中的最大值。
Input
输入的第一个数case( 0 < case < = 10 )表示测试数据的组数,对每组测试数据,首先是四个整数n,m,x,y,表示题目中的含义,接下来就是一个n*m矩阵。矩阵的每个元素小于等于1000。
Output
对于每组测试数据输出一行,表示子矩阵最大的和。
Sample Input
1 3 3 2 2 1 2 3 4 5 6 7 8 9
Sample Output
28方法一: 二维树状数组#include<stdio.h> #include<string.h> int n,m,x,y; __int64 a[1001][1001]; __int64 c[1001][1001]; int lowBit(int t) { return t & (t ^ (t-1)); } void change(int i, int j, __int64 k) { int t; while(i<=n) { t=j; while(t<=m) { c[i][t]+=k; t+=lowBit(t); } i+=lowBit(i); } } __int64 sum(int i,int j) { __int64 p=0; int t; while(i>0) { t=j; while(t>0) { p+=c[i][t]; t-=lowBit(t); } i-=lowBit(i); } return p; } int main() { int cas; int p,q; int i,j; __int64 maxn; scanf("%d",&cas); while(cas--) { memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); scanf("%d%d%d%d",&n,&m,&x,&y); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%I64d",&a[i][j]); change(i,j,a[i][j]); } maxn=-999999999; for(i=0;i+x<=n;i++) for(j=0;j+y<=m;j++) { __int64 sum1=sum(i+x,j+y); __int64 sum2=sum(i,j); __int64 sum3=sum(i+x,j); __int64 sum4=sum(i,j+y); __int64 tmp=sum1-sum3-sum4+sum2; if(tmp>maxn) maxn=tmp; } printf("%I64d\n",maxn); } return 0; } /* 5 4 4 2 2 1 1 2 2 1 1 2 2 3 3 4 4 3 3 4 4 3 3 2 2 1 2 3 4 5 6 7 8 9 */
下面是可以1s以内过的代码
#include<stdio.h> #include<string.h> int dp[1005][1005]; int main(){ int cas,n,m,x,y,i,j,k,ans; scanf("%d",&cas); while(cas--){ ans=0; scanf("%d%d%d%d",&n,&m,&x,&y); memset(dp,0,sizeof(dp)); for(i=1;i<=n;i++) for(j=1;j<=m;j++){ scanf("%d",&dp[i][j]); dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]; } for(i=x;i<=n;i++) for(j=y;j<=m;j++){ k=dp[i][j]+dp[i-x][j-y]-dp[i-x][j]-dp[i][j-y]; if(k>ans)ans=k; } printf("%d\n",ans); } return 0; }