BZOJ 1933 [Shoi2007] Bookcase 书柜的尺寸

来源:互联网 发布:编程验证歌德巴赫猜想 编辑:程序博客网 时间:2024/06/09 18:01

Description

Tom不喜欢那种一字长龙式的大书架,他只想要一个小书柜来存放他的系列工具书。Tom打算把书柜放在桌子的后面,这样需要查书的时候就可以不用起身离开了。显然,这种书柜不能太大,Tom希望它的体积越小越好。另外,出于他的审美要求,他只想要一个三层的书柜。为了物尽其用,Tom规定每层必须至少放一本书。现在的问题是,Tom怎么分配他的工具书,才能让木匠造出最小的书柜来呢? Tom很快意识到这是一个数学问题。每本书都有自己的高度hi和厚度ti。我们需要求的是一个分配方案,也就是要求把所有的书分配在S1、S2和S3三个非空集合里面的一个,不重复也不遗漏,那么,很明显,书柜正面表面积(S)的计算公式就是:  由于书柜的深度是固定的(显然,它应该等于那本最宽的书的长度),所以要求书柜的体积最小就是要求S最小。Tom离答案只有一步之遥了。不过很遗憾,Tom并不擅长于编程,于是他邀请你来帮助他解决这个问题。

Input

文件的第一行只有一个整数n(3≤n≤70),代表书本的本数。接下来有n行,每行有两个整数hi和ti,代表每本书的高度和厚度,我们保证150≤hi≤300,5≤ti≤30。

Output

只有一行,即输出最小的S。

Sample Input

4
220 29
195 20
200 9
180 30

Sample Output

18000

HINT

Source

Day2

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DP+思路~

求最大高、之和,和最大、宽之和的乘积的最小值~(注意断句!)

首先,我们可以用f[i][j][k][z]表示目前DP到第i本书,三个柜的书的宽度分别为j,k,z的最小的最大高的值,但是显然像这样所有维度都记录的话会MLE,所以我们只能记录一部分的状态。

注意到DP到i时,已有的书的宽度之和是一定的,所以我们只需要记录三块中的两块的宽度之和就可以了。而i对递推过程无影响,所以把i维换成滚动形式。

所以用f[kkz][j][k]表示目前用kkz^1更新kkz,三个书柜宽度分别为j,k,sum[i-1]-j-k的最小的最大高度,然后预处理出宽度的前缀和sum[i],直接DP即可~


#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;int n,f[2][2101][2101],inf,kkz,sum[71],h,w,ans;struct node{int h,w;}a[71];bool operator <(node u,node v){return u.h>v.h;}int read(){int totnum=0,f=1;char ch=getchar();while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') {totnum=(totnum<<1)+(totnum<<3)+ch-'0';ch=getchar();}return totnum*f;}int main(){n=read();for(int i=1;i<=n;i++) a[i].h=read(),a[i].w=read();memset(f[kkz],127/3,sizeof(f[kkz]));ans=inf=f[kkz][0][0];f[kkz][0][0]=0;sort(a+1,a+n+1);for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].w;for(int i=1;i<=n;i++){kkz^=1;h=a[i].h;w=a[i].w;memset(f[kkz],127/3,sizeof(f[kkz]));for(int j=sum[i-1];~j;j--)  for(int k=sum[i-1];~k;k--)    if(j+k<=sum[i-1] && f[kkz^1][j][k]<inf)    {    if(j) f[kkz][j+w][k]=min(f[kkz][j+w][k],f[kkz^1][j][k]);    else f[kkz][w][k]=min(f[kkz][j][k],f[kkz^1][j][k]+h);    if(k) f[kkz][j][k+w]=min(f[kkz][j][k+w],f[kkz^1][j][k]);    else f[kkz][j][w]=min(f[kkz][j][w],f[kkz^1][j][k]+h);    if(j+k<sum[i-1]) f[kkz][j][k]=min(f[kkz][j][k],f[kkz^1][j][k]);    else f[kkz][j][k]=min(f[kkz][j][k],f[kkz^1][j][k]+h);    }}for(int i=1;i<sum[n];i++)  for(int j=1;j<sum[n];j++)    if(i+j<sum[n] && f[kkz][i][j]<inf)      ans=min(ans,max(max(i,j),sum[n]-i-j)*f[kkz][i][j]);printf("%d\n",ans);return 0;}


1 0