您的位置:首页 > 大数据 > 人工智能

usaco training 6.1.2 A Rectangular Barn 题解

2014-03-17 20:28 267 查看
转载请注明出处: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息