bzoj1910: [Ctsc2002] Award 颁奖典礼
1910: [Ctsc2002] Award 颁奖典礼
Time Limit: 5 Sec Memory Limit: 259 MBSubmit: 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
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;
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;
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\n",ans); 56 }