usaco training 6.1.2 A Rectangular Barn 题解

转载请注明出处:http://blog.csdn.net/jiangshibiao/article/details/21406415

【原题】

A Rectangular Barn

Mircea Pasoi -- 2003

Ever the capitalist, Farmer John wants to extend his milking business by purchasing more cows. He needs space to build a new barn for the cows.

FJ purchased a rectangular field with R (1 ≤ R ≤ 3,000) rows numbered 1..R and C (1 ≤ C ≤ 3,000) columns numbered 1..C. Unfortunately, he realized too late that some 1x1 areas in the field are damaged, so he cannot build the barn on the entire RxC field.

FJ has counted P (0 ≤ P ≤ 30,000) damaged 1x1 pieces and has asked for your help to find the biggest rectangular barn (i.e., the largest area) that he can build on his land without building on the damaged pieces.

PROGRAM NAME: rectbarn

INPUT FORMAT

  • Line 1: Three space-separated integers: R, C, and P.
  • Lines 2..P+1: Each line contains two space-separated integers, r and c, that give the row and column numbers of a damaged area of the field

SAMPLE INPUT (file rectbarn.in)

3 4 2
1 3
2 1

OUTPUT FORMAT

  • Line 1: The largest possible area of the new barn

SAMPLE OUTPUT (file rectbarn.out)

6

OUTPUT DETAILS

  1 2 3 4
 +-+-+-+-+
1| | |X| |
 +-+-+-+-+
2|X|#|#|#|
 +-+-+-+-+
3| |#|#|#|
 +-+-+-+-+
Pieces marked with 'X' are damaged and pieces marked with '#' are part of the new barn. 


【大意】给定一个矩阵,有部分地方有“破损”,求不含破损的最大面积。

【序言】上次在单调队列中讲得太粗糙了,我又好好理解了一遍。还有,USACO的滚存啊~~~

【分析】这里我们要用到极大化的思想。

我们设h[i][j]表示从i,j这个点(包括它)一直向上,一共有几个连续的未破损的方格。

再设l[i][j]表示在h[i][j]的情况下,整一列h[i][j]向左最多能拓展到的位置的坐标。r[i][j]同理。如图。

    现在i=4,j=5。当前的h[i][j]显然是3。l[i][j]是什么呢?我们观察,高度为3的这一列最多只能再向左拓展一格,所以l[i][j]显然是4。同理,r[i][j]是5。更新结果的时候,当前面积显然是h[i][j]*(r[i][j]-l[i][j]+1)。

【转移】然则怎么转移呢?h[i][j]很好办,直接转移就行了。至于l[i][j]有点麻烦,因为它和好几行的状态有关。

l[i][j]=max(l[i-1][j],tl[j])。首先解释一下为什么是max。因为l[i][j]存的是坐标。虽然是去最少的拓展数,但是坐标要取max;相反,r[i][j]就是取min。tl[j]表示这一行向左最多能拓展几格,而l[i-1][j]保存着上一行的结果。

特殊地,当(i,j)这个位置是被破坏的时候,l[i][j]和r[i][j]分别置为最小和最大(1和m),防止下面更新时出错。

【注意】USACO有坑爹的内存限制,因此除了记录是否为破损的数组外,其他都尽量开滚存。

【代码】

/*
PROG:rectbarn
ID:juan1973
LANG:C++
*/
#include<stdio.h>  
#include<iostream>  
#include<cstring>
using namespace std;  
const int maxn=3000+5;  
bool a[maxn][maxn];  
int h[2][maxn],l[2][maxn],r[2][maxn],tl[maxn],tr[maxn];  
int n,m,i,j,ans,temp,x,y,p,now;  
int main()  
{  
  freopen("rectbarn.in","r",stdin);  
  freopen("rectbarn.out","w",stdout);  
  scanf("%ld%ld%ld",&n,&m,&p);  
  memset(a,1,sizeof(a));
  for (i=1;i<=p;i++)  
  {  
    scanf("%ld%ld",&x,&y);
    a[x][y]=false;
  }  
  for (j=1;j<=m;j++)
    if (a[1][j]) h[1][j]=1;else h[1][j]=0;
  l[1][1]=1;
  for (j=2;j<=m;j++)   
    if (a[1][j])   
      {  
        if (!a[1][j-1]) l[1][j]=j;  
        else l[1][j]=l[1][j-1];  
      }  
      else {l[1][j]=1;r[1][j]=m;}
  r[1][m]=m;
  for (j=m-1;j>0;j--)  
    if (a[1][j])  
      {  
        if (!a[1][j+1]) r[1][j]=j;  
        else r[1][j]=r[1][j+1];  
      }  
  now=1;
  for (i=2;i<=n;i++)  
  {  
    now^=1;
    for (j=1;j<=m;j++)
      if (a[i][j]) {h[now][j]=h[now^1][j]+1;} 
      else {l[now][j]=1;r[now][j]=m;h[now][j]=0;}
    for (j=1;j<=m;j++)   
      if (a[i][j])   
      {  
        if (tl[j-1]==0) tl[j]=j;  
        else tl[j]=tl[j-1];  
      }  
     else tl[j]=0;
    for (j=m;j>0;j--)  
      if (a[i][j])  
      {  
        if (tr[j+1]==0) tr[j]=j;  
        else tr[j]=tr[j+1];  
      }  
      else tr[j]=0;  
    for (j=1;j<=m;j++)  
      if (a[i][j])  
      {  
        l[now][j]=max(l[now^1][j],tl[j]);  
        r[now][j]=min(r[now^1][j],tr[j]);  
        temp=h[now][j]*(r[now][j]-l[now][j]+1);  
        if (temp>ans)   
          ans=temp;  
      }    
  }  
  
  printf("%ld\n",ans);  
  return 0;  
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值