题目背景
王7的生日到了,他的弟弟准备送他巧克力。
题目描述
有一个被分成n*m格的巧克力盒,在(i,j)的位置上有a[i,j]块巧克力。就在送出它的前一天晚上,有老鼠夜袭巧克力盒,某些位置上被洗劫并且穿了洞。所以,你——王7的弟弟王9,必须从这个满目苍夷的盒子中切割出一个矩形巧克力盒,其中不能有被老鼠洗劫过的格子且使这个盒子里的巧克力尽量多。
输入输出格式
输入格式:
第一行有两个整数 n、m。第 i+1行的第 j 个数表示a[ i , j ]。如果这个数为 0 ,则表示这个位置的格子被洗劫过。
输出格式:
输出最大巧克力数。
输入输出样例
输入样例#1:
3 4
1 2 3 4
5 0 6 3
10 3 4 0
输出样例#1:
17
//10 3 4这个矩形的巧克力数最大
说明
1≤n,m≤300
0≤a[i,j]≤255
题目大意:求不含0的最大子矩形的权值和
题解:
二维前缀和暴力50
#include<iostream> #include<cstdio> #include<cstring> #define inf 100000000 using namespace std; int ans,n,m,map[310][310],sum[310][310]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); if(!map[i][j])map[i][j]=-inf; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+map[i][j]; } } for(register int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(register int chang=1;chang+j-1<=m;chang++){ for(int kuan=1;kuan+i-1<=n;kuan++){ int x=i+kuan-1,y=j+chang-1; int gg=sum[x][y]-sum[i-1][y]-sum[x][j-1]+sum[i-1][j-1]; if(gg>ans)ans=gg; } } } } printf("%d ",ans); return 0; }
正解:预处理每列的前缀和 然后枚举子矩形的上下边界 更新答案
#include<iostream> #include<cstdio> #include<cstring> #define inf 1000000 using namespace std; int ans,n,m,sum[310][310]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&sum[i][j]); if(!sum[i][j])sum[i][j]=-inf; sum[i][j]+=sum[i-1][j]; } } for(int tu=0;tu<n;tu++){ for(int dn=tu+1;dn<=n;dn++){ int cnt=0; for(int i=1;i<=m;i++){ if(cnt<0)cnt=sum[dn][i]-sum[tu][i]; else cnt+=sum[dn][i]-sum[tu][i]; ans=max(ans,cnt); } } } printf("%d ",ans); return 0; }