[题解]P2160 [SHOI2007] 书柜的尺寸

思路

观察到 tin 都很小,考虑从此切入。

定义 dpi,a,b,c 表示用前 i 本书,第一层厚 a,第二层厚 b,第三层厚 c 的三层最小总高度。

然后你就发现 c 这一维是完全可以被 sumab 计算出来的,可以优化掉。

由于中途插入一本书,可能会导致这层的高度发生改变。于是将书按照高度排序,每一层放入的第一本书都是高度最高的。

接下来的转移就比较轻松了。

时间复杂度 Θ(n(ti)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;
}

作者:WaterSun

出处:https://www.cnblogs.com/WaterSun/p/18317328

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   WBIKPS  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示