http://codewaysky.sinaapp.com/problem.php?id=1056
这题和奶牛浴场略有区别,奶牛浴场只需要求出最大子矩形,而这题要求的是最大权重子矩形,不一定要最大的面积,但要最大的权重和
思路是先求出每个最大子矩形,然后求出每个矩形的左上点和右下点,然后用二维数转数组进行求和,保存最优解
View Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<stdio.h> 5 #include<memory.h> 6 using namespace std; 7 8 int sum[1010][1010]; 9 int v[1010][1010]; 10 int l[1010],r[1010],h[1010]; 11 int n,m; 12 13 //****************************//树状数组 14 int lowbit(int x) 15 { 16 return x&-x; 17 } 18 19 void add(int x,int y,int w) 20 { 21 int i,j; 22 for(i=x;i<=n;i+=lowbit(i)) 23 { 24 for(j=y;j<=m;j+=lowbit(j)) 25 sum[i][j]+=w; 26 } 27 } 28 29 int get_sum(int x,int y) 30 { 31 int i,j,ans=0; 32 for(i=x;i>0;i-=lowbit(i)) 33 { 34 for(j=y;j>0;j-=lowbit(j)) 35 { 36 ans+=sum[i][j]; 37 } 38 } 39 return ans; 40 } 41 //*****************************// 42 43 int find(int x1,int y1,int x2,int y2) 44 { 45 return get_sum(x2,y2)-get_sum(x1-1,y2)-get_sum(x2,y1-1)+get_sum(x1-1,y1-1); 46 } 47 48 int main() 49 { 50 int i,j,w,x1,x2,y1,y2; 51 freopen("D:\\in.txt","r",stdin); 52 while(scanf("%d%d",&n,&m)==2) 53 { 54 memset(sum,0,sizeof(sum)); 55 memset(v,0,sizeof(v)); 56 for(i=1;i<=n;i++) 57 { 58 for(j=1;j<=m;j++) 59 { 60 scanf("%d",&w); 61 if(!w) 62 v[i][j]=1; 63 else 64 add(i,j,w); 65 } 66 } 67 for(i=0;i<=m;i++) 68 { 69 h[i]=0;l[i]=1;r[i]=m; 70 } 71 int lm,rm,ans=0,temp; 72 for(i=1;i<=n;i++) 73 { 74 lm=1; 75 for(j=1;j<=m;j++) 76 { 77 if(!v[i][j]) 78 { 79 h[j]++; 80 if(lm>l[j]) 81 l[j]=lm; 82 } 83 else 84 { 85 h[j]=0; //边界不能有洞,所以障碍点高度是0,而不是1 86 l[j]=1; 87 r[j]=m; 88 lm=j+1; //由于边界不能有洞,所以加1 89 } 90 } 91 rm=m; 92 for(j=m;j>0;j--) 93 { 94 if(r[j]>rm) 95 r[j]=rm; 96 if(h[j]) 97 { 98 y1=l[j];y2=r[j]; //处理出举行的左上点和右下点 99 x1=i-h[j]+1;x2=i; 100 temp=find(x1,y1,x2,y2); //利用二维数转数组进行求和 101 if(temp>ans) 102 ans=temp; 103 } 104 else 105 rm=j-1; //同理减一 106 } 107 } 108 printf("%d\n",ans); 109 } 110 return 0; 111 }