您的位置:首页 > 其它

数字八

2016-01-12 18:35 696 查看

题目

Farmer John的奶牛最近收到一块大理石。但不幸的是,这块石头有些不完整。为了说明这块石头的状况,我们就可以用一个N*N正方形网格(5 <= N <=300)来描述,其中字符’*’代表石头的缺损部分,’.’表示石头完美无瑕的部分。

奶牛要在这一块大理石上雕刻数字“8”。然而,牛也需要FJ的帮助,以确定在这块大理石上最佳的雕刻位置。这里有几个要求来定义一个有效的数字8:

*数字8由上下两个矩形构成。

*数字8的上下两个矩形都满足至少有一个单元格在矩形内部,也就是说两个矩形都至少是3*3的。

*数字8顶部的矩形的底边必须为底部矩形顶边的子集。

*数字8只能刻在大理石完美无瑕的部分。

*规定数字8的得分为上矩形和下矩形的面积的乘积。

请确定奶牛所能构造的最大数字8.




上面的矩形面积为6*9=54,下面的矩形面积为12*6,得分为54*72=3888

5 <= N <=300

分析

数据范围告诉我们这题可以接受n^3的情况。

所以我们考虑如何dp。

我们设f[i,j,k]为从第i到第j列从第k行往上的最大面积。

同理我们可以算出g[i,j,k]

那么答案可以枚举i,j,k,但是这时我们不能再枚举去求f的范围了。

怎么办呢?很好解决的,我们还是原来的g[i,j,k],只不过我们可以把它的限定改一改

改为不超过i,j的范围的最大的面积即可。

所以这题便可以以n^3过掉了。

[code]#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=305;
int n,a

,sum

,f

;
char str
;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%s",str);
        for(int j=1;j<=n;j++) {
        if (str[j]=='.')a[i][j]=0;else a[i][j]=1;
        sum[i][j]=sum[i][j-1]+a[i][j];
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            int len=0;
           for(int k=1;k<=n;k++){
                if (a[k][i]||a[k][j]) len=0;
                if (!(sum[k][j]-sum[k][i-1]))
                if (len) f[k][i][j]=(j-i-1)*(k-len-1);else len=k;
           }
    }
    for(int k=1;k<=n;k++)
       for(int i=1;i<=n;i++){
           for(int j=1;j<=n&&j+k<=n;j++)
            if (!(sum[i][j+k]-sum[i][j-1]))f[i][j][j+k]=max(max(f[i][j][j+k],f[i][j][j+k-1]),f[i][j+1][j+k]);
       }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            int len=0;
           for(int k=n;k;k--){
                if (a[k][i]||a[k][j]) len=0;
                if (!(sum[k][j]-sum[k][i-1]))
                if (len)ans=max(ans,(j-i-1)*(len-k-1)*f[k][i][j]);else len=k;
           }
    }
    if (!ans) printf("-1");else printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: