[题解]P2160 [SHOI2007] 书柜的尺寸
思路
观察到 \(t_i\) 和 \(n\) 都很小,考虑从此切入。
定义 \(dp_{i,a,b,c}\) 表示用前 \(i\) 本书,第一层厚 \(a\),第二层厚 \(b\),第三层厚 \(c\) 的三层最小总高度。
然后你就发现 \(c\) 这一维是完全可以被 \(sum - a - b\) 计算出来的,可以优化掉。
由于中途插入一本书,可能会导致这层的高度发生改变。于是将书按照高度排序,每一层放入的第一本书都是高度最高的。
接下来的转移就比较轻松了。
时间复杂度 \(\Theta(n(\sum{t_i})^2)\),空间复杂度可以滚动掉 \(n\)。
注意判断答案的合法性。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 110,M = 3010,inf = 1e9 + 10;
int n,cnt,ans = inf;
int r,dp[2][M][M];
struct point{
int h,d;
inline bool friend operator <(const point &a,const point &b){
return a.h > b.h;
}
}arr[N];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
int main(){
n = read();
for (re int i = 1;i <= n;i++){
arr[i].h = read(); arr[i].d = read();
cnt += arr[i].d;
}
sort(arr + 1,arr + n + 1);
for (re int i = 0,sum = 0;i < n;i++){
sum += arr[i].d;
for (re int a = 0;a <= cnt;a++){
for (re int b = 0;a + b <= cnt;b++) dp[r ^ 1][a][b] = inf;
}
for (re int a = 0;a <= sum;a++){
for (re int b = 0;a + b <= sum;b++){
int c = sum - a - b;
if (dp[r][a][b] == inf) continue;
if (!a) dp[r ^ 1][arr[i + 1].d][b] = min(dp[r ^ 1][arr[i + 1].d][b],dp[r][a][b] + arr[i + 1].h);
else dp[r ^ 1][a + arr[i + 1].d][b] = min(dp[r ^ 1][a + arr[i + 1].d][b],dp[r][a][b]);
if (!b) dp[r ^ 1][a][arr[i + 1].d] = min(dp[r ^ 1][a][arr[i + 1].d],dp[r][a][b] + arr[i + 1].h);
else dp[r ^ 1][a][b + arr[i + 1].d] = min(dp[r ^ 1][a][b + arr[i + 1].d],dp[r][a][b]);
if (!c) dp[r ^ 1][a][b] = min(dp[r ^ 1][a][b],dp[r][a][b] + arr[i + 1].h);
else dp[r ^ 1][a][b] = min(dp[r ^ 1][a][b],dp[r][a][b]);
}
}
r ^= 1;
}
for (re int i = 1;i <= cnt;i++){
for (re int j = 1;i + j <= cnt;j++){
int k = cnt - i - j;
if (dp[r][i][j] != inf && k) ans = min(ans,max({i,j,k}) * dp[r][i][j]);
}
}
printf("%d",ans);
return 0;
}

浙公网安备 33010602011771号