您的位置:首页 > 其它

数字8(eight )题解

2015-08-22 20:31 381 查看

题目描述

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: