[OIBH] 糖果盒(Candy Box)——又一个最大子矩形

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 }
posted @ 2012-09-30 14:55  Accept  阅读(791)  评论(0编辑  收藏  举报