题意:
将n本书放入一个三层的书架,求书架的最小面积。
分析:
定义dp[i][j][k]为对于前i本书,第二个书架的宽度为j,第三个书架的宽度为k时书架的最小总高度,我们规定最高的书放在第一个书架。在开数组时可以省掉一维,则有转移方程:
if(j>b[i].w)
dp[j][k]=min(dp[j-b[i].w][k],dp[j][k]);
if(j==b[i].w)
dp[j][k]=min(dp[0][k]+b[i].h,dp[j][k]);
if(k>b[i].w)
dp[j][k]=min(dp[j][k-b[i].w],dp[j][k]);
if(k==b[i].w)
dp[j][k]=min(dp[j][0]+b[i].h,dp[j][k]);
但单纯这个会超时。
但是注意到每行的最大的宽度不超过总宽度的一半(具体证明我也不太会,只是感觉有点道理。以后开窍了再来补QAQ)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2100;
#define inf 0x3f3f3f3f
int T,n;
struct Node{
int h,w;
bool operator < (const Node &t) const {
return h>t.h;
}
}node[100];
int dp[maxn][maxn],sum[100];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int maxh=0,sumw=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&node[i].h,&node[i].w);
maxh=max(maxh,node[i].h);
sumw+=node[i].w;
}
sort(node+1,node+1+n);
sum[0]=0;
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+node[i].w;
}
int len=sumw/2;
for(int i=0;i<=len;i++)
for(int j=0;j<=len;j++) dp[i][j]=inf;
dp[0][0]=maxh;
for(int k=2;k<=n;k++){
for(int i=min(sum[k],len);i>=0;i--){
for(int j=min(sum[k]-i,len);j>=0;j--){
if(i-node[k].w>0) dp[i][j]=min(dp[i][j],dp[i-node[k].w][j]);
if(i-node[k].w==0) dp[i][j]=min(dp[i][j],dp[0][j]+node[k].h);
if(j-node[k].w>0) dp[i][j]=min(dp[i][j],dp[i][j-node[k].w]);
if(j-node[k].w==0) dp[i][j]=min(dp[i][j],dp[i][0]+node[k].h);
}
}
}
int ans=inf;
for(int i=1;i<=len;i++){
for(int j=1;j<=len;j++){
if(i+j>=sumw||dp[i][j]==(int)inf) continue;
ans=min(ans,dp[i][j]*max(sumw-i-j,max(i,j)));
}
}
printf("%d\n",ans);
}
return 0;
}