数字8(eight )题解

来源:互联网 发布:北京久其软件 编辑:程序博客网 时间:2024/05/16 12:09

题目描述

Farmer的奶牛近收到一块大理石。但这块块石头有些不完整。

为了说明这块石头的状况,我们就可以用一个N*N正方形网格(5<= N <=300)来描述,其中字符’*’代表石头的缺损部分,’.’表示石头完美无瑕的部分。奶牛要在这块大理石上雕刻一个数字”8”。

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

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

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

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

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

*规定数字8的得分为上矩形和下矩形的面积的乘积,它们希望得分能达到最大。

例如,给出这样的一块大理石:
这里写图片描述
最优的8摆放位置如下图所示:
这里写图片描述
上矩形的面积为6*9=54,下矩形的面积则是12*6=72。所以,它的得分就是54*72=3888。

输入

第一包括一个整数N,代表大理石的边长。

第二到N+1行,每一行描述了大理石的一行,包含着N个字符,每一个字符是”*”(代表缺损的部分)与”.”(代表完美无瑕的部分)其中一个

输出

第一包含一个整数,代表符合条件数字8中最大的得分。若没有一个合法的数字8,请输出-1。

样例输入

15
……………
……………
*…..
.….…….*
.……….*.
….*……….
…***….
……………
..*.....
…*.*….
..…*…….
……………
…....……
………*…..
……………

样例输出

3888

提示

对于30% 的数据,5<=N<=80。

对于100%的数据,5<=N<=300。

想法

  • 上下可以分开考虑
  • 最优化问题考虑动态规划
  • 数据范围在空间与时间上都考虑O(n^3)的算法

算法

  • f[i][l][r]表示第i行 选取l为左端点 r为右端点的线段为下边的上方矩形的最大面积
  • g[i][l][r]表示第i行 选取l为左端点 r为右端点的线段为上边的下方矩形的最大面积
  • 显然f g都是可以在O(n^3)的时间内处理出来
  • 以f为例 从上到下扫描 找到最上面的符合要求的上边
  • 根据题目要求 上矩形下边要为下矩形上边的子集 考虑改变f数组的意义
  • f[i][l][r]改为表示f[i][l][r] 第i行 左右端点分别在[l,r]区间内的最大矩形面积
  • 显然f[i][l][r]=max(f[i][l][r],f[i][l+1][r],f[i][l][r-1]);

代码

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cmath>#include <cstring>#include <string>using namespace std;int map[310][310],n,sum[310][310],f[310][310][310],g[310][310][310];typedef long long ll;ll ans=-1,cnt;char ch;int main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)        {            scanf(" %c",&ch);            map[i][j]=(ch=='*');            sum[i][j]=sum[i][j-1]+map[i][j];        }    for (int i=1;i<=n-2;i++)        for (int j=i+2;j<=n;j++)        {            int p=0;            for (int k=1;k<=n;k++)            {                if(map[k][i]||map[k][j])p=0;                if(!(sum[k][j]-sum[k][i-1]))                    p?f[k][i][j]=(j-i-1)*(k-p-1):p=k;            }            p=0;            for (int k=n;k>=1;k--)            {                if(map[k][i]||map[k][j])p=0;                if(!(sum[k][j]-sum[k][i-1]))                    p?g[k][i][j]=(j-i-1)*(p-k-1):p=k;            }        }    for (int k=1;k<=n;k++)    {        for (int i=1;i<n-2;i++)            for (int j=i+3;j<=n&&!(sum[k][j]-sum[k][i-1]);j++)                f[k][i][j]=max(f[k][i][j],f[k][i][j-1]);        for (int j=n;j>3;j--)            for (int i=j-3;i>=0&&!(sum[k][j]-sum[k][i-1]);i--)                f[k][i][j]=max(f[k][i][j],f[k][i+1][j]);    }    for (int k=3;k<n;k++)    {        for (int i=1;i<n-1;i++)            for (int j=i+2;j<=n;j++)            {                cnt=f[k][i][j]*g[k][i][j];                if(!(sum[k][j]-sum[k][i-1])&&cnt)ans=max(ans,cnt);            }    }    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击