hdu 1505 City Game && hdu 1506 Largest Rectangle in a Histogram

之所以把这两题放一块呢。。。是因为1505 是1506的深化!

1506是求最大矩形覆盖(说到这里,我觉得好多覆盖问题都是用dp解决的啊,有树上的最少覆盖条件:

昨天做的那个 POJ 1463 && HDU 1054 Strategic Game (树形DP)有线性问题的覆盖,比如这两题)

hdu 1506 和那个POJ 2796 Feel Good应该就是一样的。代码略改就可以提交了。

都是向左右找比当前位置大的数,记录能延伸到的最远距离,只是这题矩形的宽度是1,比那题还要简单。


要注意的是开始写的向两边找没有用到dp中递推的思想,而是每次都找一遍tle了。。

下面看一下tle的代码:需要优化的地方在里面有标注

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

__int64 a[100010];
int le[100010],ri[100010];
__int64 dp[100010];

int main()
{
    int n,tmp;
    __int64 ans;
    while(scanf("%d",&n)&&n)
    {
        memset(dp,0,sizeof(dp));
        memset(le,0,sizeof(le));
        memset(ri,0,sizeof(ri));

        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)  //可以用递推优化。
        {
            tmp=i;
            while( tmp>=1 &&a[tmp]>=a[i])
                tmp--;
            le[i]=tmp+1;
        }
        for(int i=1;i<=n;i++)
        {
            tmp=i;
            while(tmp<=n && a[tmp]>=a[i])
                tmp++;
            ri[i]=tmp-1;
        }
        //for(int i=1;i<=n;i++)
         //   printf("%d %d %d %d\n",i,a[i],le[i],ri[i]);
        ans=-1;
        for(int i=1;i<=n;i++)
        {
            dp[i]=a[i]*(ri[i]-le[i]+1);
            if(dp[i]>ans)
                ans=dp[i];
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

//HDU 1506
//tle

然后就是利用了找最优子结构的思想,把左右的最大延伸范围记录下来

只需要和相邻的比较就可以了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<stack>
#include<vector>
#include<queue>
using namespace std;

__int64 a[100010];
int l[100010],r[100010];
__int64 ans,tmp;

int main()
{
    int n,minn,le,ri;
    while(scanf("%d",&n)&&n)
    {

        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
            l[i]=r[i]=i;
        }

        for(int i=2;i<=n;i++)
        {
            while(l[i]>1 && a[l[i]-1]>=a[i])  //要注意的地方。
                l[i]=l[l[i]-1];
        }

        for(int i=n-1;i>=0;i--)
        {
            while(r[i]<n && a[r[i]+1]>=a[i])
                r[i]=r[r[i]+1];
        }
        ans=-1;
        for(int i=1;i<=n;i++)
        {
            tmp=a[i]*(r[i]-l[i]+1);
            if(tmp>ans)
            {
                ans=tmp;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}


hdu 1505 可以转化为 在一个01 矩阵里面找一个最大的全 0 矩阵 , 先求出每个 0 能够向上找到的 0 的个数 。

然后像1506那样逐行进行类似的运算求最大值。


#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

int a[1005][1005];
int le[1005],ri[1005];

int main()
{
    int T,tmp,ans,m,n;
    char str[10];
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));

        scanf("%d%d",&m,&n);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%s",str);
                if(str[0]=='F')
                    a[i][j]=a[i-1][j]+1;
                else a[i][j]=0;
            }
        }
        /*for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%d ",a[i][j]);
            printf("\n");
        }*/
        ans=-1;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)   //每次都要重新把le[j]和ri[j]
                le[j]=ri[j]=j;       //初始化为本身
            for(int j=2;j<=n;j++)
            {
                if(le[j]>1 && a[i][le[j]-1]>=a[i][j])
                    le[j]=le[le[j]-1];
            }
            for(int j=n-1;j>=1;j--)
            {
                if(ri[j]<n && a[i][ri[j]+1]>=a[i][j])
                    ri[j]=ri[ri[j]+1];
            }
            for(int j=1;j<=n;j++)
            {
                tmp=a[i][j]*(ri[j]-le[j]+1);
                if(tmp>ans)
                    ans=tmp;
            }
        }
        printf("%d\n",ans*3);
    }
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值