[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 }

你可能感兴趣的:(ca)