BZOJ 1933 Bookcase 书柜的尺寸
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
F[I][J][K]表示操作到第i本书,第一层的书的厚度为J,第二层书的厚度为K,则第三层的厚度为SUM[I]-I-J,记录的是最小的高度。(按照高度从小到大排序,这样就没有后效性了) 时间复杂度O(70*2100*2100),空间复杂度O(2*2100*2100) 开滚动数组
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define ll long long
#define maxn 4001000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI 2*asin(1)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define SWAP(x,y,t) ( (t)=(x),(x)=(y),(y)=(t) )
using namespace std;
struct node{
int h,t;
}a[1010];
int f[2][2110][2110];
int n,sum[1010],ans=10101010;
bool cmp(node a,node b)
{
return a.h>b.h;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].h,&a[i].t);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].t;
memset(f,127/3,sizeof(f));
f[0][0][0]=0;
int sta=0;
for(int i=1;i<=n;i++)
{
sta=!sta;
memset(f[sta],127/3,sizeof(f[sta]));
for(int j=sum[i-1];j>=0;j--)
for(int k=sum[i-1];k>=0;k--)
{
if(j+k>sum[i-1]||f[!sta][j][k]>101010) continue;
int t=a[i].t,h=a[i].h;
if(j==0) f[sta][t][k]=min(f[sta][t][k],f[!sta][j][k]+h);
else f[sta][j+t][k]=min(f[sta][j+t][k],f[!sta][j][k]);
if(k==0) f[sta][j][t]=min(f[sta][j][t],f[!sta][j][k]+h);
else f[sta][j][k+t]=min(f[sta][j][k+t],f[!sta][j][k]);
if(sum[i-1]-k-j==0) f[sta][j][k]=min(f[sta][j][k],f[!sta][j][k]+h);
else f[sta][j][k]=min(f[sta][j][k],f[!sta][j][k]);
}
}
for(int i=1;i<sum[n];i++)
for(int j=1;j<sum[n];j++)
if(i+j<sum[n] && f[sta][i][j]<101010)
{
ans=min(ans,max(max(i,j),sum[n]-i-j)*f[sta][i][j]);
//printf("i=%d j=%d sum[n]=%d %d %d f[sta][i][j]=%d\n",i,j,sum[n],max(max(i,j),sum[n]-i-j)*f[sta][i][j],max(max(i,j),sum[n]-i-j),f[sta][i][j]);
}
printf("%d\n",ans);
}
风在前,无惧!