• bzoj1910: [Ctsc2002] Award 颁奖典礼


    1910: [Ctsc2002] Award 颁奖典礼

    Time Limit: 5 Sec  Memory Limit: 259 MB
    Submit: 183  Solved: 98
    [Submit][Status]

    Description

    IOI2002的颁奖典礼将在YONG-IN Hall隆重举行。人们在经历了充满梦幻的世界杯之后变得更加富于情趣。为了使颁奖典礼更具魅力,有人建议在YONG-IN Hall中搭建一个I字型的颁奖台,以此代表信息学Informatics。考虑到比赛的赞助商们可能要在YONG-IN Hall中摆设了许多展示台,他们可能不愿意移动展示台的位置。你作为IOI2002的金牌得主自然地成为了他们求助的对象。 YONG-IN Hall是一个矩形的网格区域。每个赞助商的展示台都占据了若干个单位网格。I型颁奖台将正向搭建,且平行于YONG-IN Hall的边缘。I型颁奖台是由三个矩形相接叠成的,其中上方和下方的矩形的两侧必须都超出中间的矩形,否则将被误解成T, L, J等字母。例如:  这是两个合法的I型颁奖台,而以下三种情况均不合法: 希望你编程寻找面积最大的I型颁奖台,使其不覆盖任何展示台。

    Input

    第一行包含两个正整数n, m(1<=n,m<=200),分别表示YONG-IN Hall的矩形网格区域的行数和列数。以下n行每行包含m个数字,非0即1,每个数字描述一个单位网格,1表示该单位网格存在展示台,0表示该单位网格不存在展示台。

    Output

    仅包含一个正整数,表示最大的I型颁奖台的面积。如果不存在合法的I型颁奖台,则输出0。

    Sample Input

    6 8
    1 1 1 1 1 0 0 1
    1 0 0 0 0 1 1 1
    1 0 0 0 0 0 1 1
    1 0 1 0 1 0 1 0
    1 0 0 0 0 0 0 1
    1 1 0 0 0 1 0 1

    Sample Output

    15

    HINT

     题意还是十分好理解的,其实也就分成三种状态来转移而已。

    【拆解题目】一个  I  其实就是3个矩形,显然可以用DP做,设f[1..3][i][j][k]表示到第1..3个矩形为止,第i行,j~k列为底的最大面积。
    这样定义可能有歧义,那就举个例子说明一下。
     
     
    然后显然的转移:
    if(  k~j都是0  )
    f[1][i][j][k]=max(f[1][i-1][j][k],0)+k-j+1;
    //为什么这里max后面有个0?因为要初始化为负的极大值。这又是为什么?因为不初始化就无法保证2号和3号矩形的上面一定有矩形,f[2][1][7][7]将=1
    f[2][i][j][k]=max(g2[i-1][j][k],f[2][i-1][j][k])+k-j+1;
    //g2[i][j][k]存储【j,k】闭区间的补集的最优值……←无视这句话,即包含区间【j,k】的最优解
    f[3][i][j][k]=max(g1[i-1][j][k],f[3][i-1][j][k])+k-j+1;
    //g1[i][j][k]是被【j,k】包含的最优解……我解释不清……不过这么水和平常的想法想必大家都懂
     1 #include<cstring>
     2 #include<cmath>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdio>
     6 #define N 207
     7 #define inf 1000000009
     8 using namespace std;
     9 
    10 int n,m,ans;
    11 
    12 int f[4][N][N][N],s[N][N],x1[N][N][N],x2[N][N][N];
    13 
    14 int main()
    15 {
    16     scanf("%d%d",&n,&m);
    17     memset(x1,192,sizeof(x1));
    18     memset(x2,192,sizeof(x2));
    19     memset(f,192,sizeof(f));//先赋值为一个最大值。 
    20     for (int i=1;i<=m;i++)
    21         for (int j=1;j<=m;j++)
    22             f[1][0][i][j]=0;//第零行初始化为0,表示没有长度。 
    23     int x;
    24     for (int i=1;i<=n;i++)
    25         for (int j=1;j<=m;j++)
    26             {
    27                 scanf("%d",&x);
    28                 s[i][j]=s[i][j-1]+x;//处理前缀和。 
    29             }
    30     for (int i=1;i<=n;i++)
    31     {
    32         for (int j=1;j<=m;j++)
    33             for (int k=j;k<=m;k++)
    34             if (s[i][k]-s[i][j-1]==0)//如果这一段都是空地的话。 
    35             {
    36                 f[1][i][j][k]=max(f[1][i-1][j][k],0)+k-j+1;//如果上一层是有的话,就继续转移。 
    37                 f[2][i][j][k]=max(x2[i-1][j][k],f[2][i-1][j][k])+k-j+1;//也是一样的道理,从上一层的最大值来转移。 
    38                 f[3][i][j][k]=max(x1[i-1][j][k],f[3][i-1][j][k])+k-j+1;
    39                 ans=max(ans,f[3][i][j][k]);//ans每次从当前I型中取最大值。 
    40             }
    41         for (int l=0;l<=m-1;l++)
    42             for (int j=1;j+l<=m;j++)
    43             {
    44                 int k=j+l;
    45                 x1[i][j][k]=max(max(x1[i][j+1][k],x1[i][j][k-1]),f[2][i][j+1][k-1]);//x1数组是用来更新第三块矩阵的,代表了第二号矩阵。 
    46             }        
    47         for (int l=m-1;l>=0;l--)
    48             for (int j=1;j+l<=m;j++)
    49             {
    50                 int k=j+l;
    51                 x2[i][j][k]=max(max(x2[i][j-1][k],x2[i][j][k+1]),f[1][i][j-1][k+1]);//x2数组是用来更新第二块矩阵的,代表了第一号矩阵。 
    52             }
    53         //x1,x2表示衔接矩阵。    
    54     }
    55     printf("%d
    ",ans);
    56 }
  • 相关阅读:
    规格说明书-----吉林1日游
    每周代码及工作总结(第九周)
    评论beta发布
    每周代码及工作总结(第八周)
    半年之后没啥意思,开个博客
    本周例行报告
    final发布评论Ⅱ
    课堂final发布
    本周例行报告
    回顾
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7632849.html
Copyright © 2020-2023  润新知