这道dp算是同类型dp中比较难的了,主要难点在于设置状态上;

如果像平时那样设置,必定爆空间没商量;

下面是一种思路:

先把输入进来的数据按h从大到小排序,这样就可以大大减少状态数,

然后设f[i][j][k]为前i本书第一个书柜厚度j,第二个书柜厚度k,第三个书柜厚度sum[i]-j-k的h最大值得最小和;

这样一是将h放在了里面,相当于一个方程思想,因为s可以由h,t算出来;

二是转移的时候,如果j,k或sum[i]-j-k为0,直接加上h,因为前面的h比后面的大,方便了转移;

但我最后也是心惊胆战的交了上去,幸运地A了;

这种题还是做的太少了,加油吧;

自己都不忍直视的代码->

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
#define LL long long
const long long inf=1000000000LL;
int n,c=;
struct node{
int h,t;
bool operator<(const node& b)const{return h>b.h;}
}e[];
LL f[][],sum[];
void init(){
scanf("%d",&n);
for(int i=;i<=n;i++){scanf("%d%d",&e[i].h,&e[i].t);c+=e[i].t;}
sort(e+,e+n+);
for(int i=;i<=n;i++)sum[i]=sum[i-]+e[i].t;
}
void work(){
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++){
for(int j=c/+;j>=;j--)
for(int k=c/+;k>=;k--){
if(sum[i]-j-k==e[i].t)f[j][k]+=e[i].h;
if(j<e[i].t&&k<e[i].t)continue;
if(j==e[i].t)f[j][k]=min(f[j][k],f[j-e[i].t][k]+e[i].h);
if(j>e[i].t)f[j][k]=min(f[j][k],f[j-e[i].t][k]);
if(k==e[i].t)f[j][k]=min(f[j][k],f[j][k-e[i].t]+e[i].h);
if(k>e[i].t)f[j][k]=min(f[j][k],f[j][k-e[i].t]);
}
}
long long ans=10000000000LL;
for(int j=;j<=c/+;j++)
for(int k=;k<=c/+;k++){
if(c-j-k<=)break;
ans=min(ans,(f[j][k]>=inf?inf:f[j][k])*max(max(j,k),c-j-k));
}
cout<<ans<<endl;
}
int main(){
init();
work();
return ;
}
05-07 15:38