POJ3124.The Bookcase(题解)

思路:我们发现一共需要求两维东西,一个是宽度,另一个是高度,那么依据我们的经验,可以将高度首先进行一次排序。那么是由高到低排好,还是由低到高排好呢?

  • 考虑由低到高,显然每一次加入一个东西\(i\)时,该东西一定是最高的,该东西加入的那一排,高度一定是\(h[i]\),但是有一个问题是我们还需要知道其他两维的高度,那么我们必须再开两维数组来表示,显然解决了一部分问题,但是并不能完全解决问题。
  • 考虑由高到低,由高到低一个最大的好处就是,这三排中的\(Max_high\)一定在头部,此时我们如果用数组来表示宽度的话,那么如果宽度不为0,就代表这一排前面一定有比这个高的,高度不会改变,所以我们能够用一维来表示两维能表示的东西,很好的解决了这个问题。
    因为我们需要求最小面积 = \(\sum Max\_high * \sum Max\_width\),又发现了宽度可以继续表示高度,那么我们就设\(f(i,j,k)\)代表当前进行到第\(i\)个物品,且第一排第二排宽度分别为\(j,k\)时最小高度,状态转移方程:
    \(f[i,j,k] = min(f[i-1,j,k] + (sum\_now - j - k == 0?h[i]:0),f[i-1,j-w[i],k] + (j-w[i] == 0?h[i]:0),f[i-1,j,k-w[i]] + (k-w[i] == 0?h[i]:0))\)
    最后扫描一遍原数组得到答案。
    这个题我们需要做到两维才能够AC,发现转移方程中\(i\)是由\(i-1\)转移,那么一个显而易见的想法是开滚动数组(然而我还是过不了,因此后两维枚举时倒着枚举,这样就能够AC了。详情见代码:
    \(Code:\)
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define ch() getchar()
#define pc(x) putchar(x)
#define rep(i, a, b) for (int i = a; i <= b; ++i)
#define bep(i, a, b) for (int i = a; i >= b; --i)
#define lowbit(x) x &(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template <typename T>
void read(T &x) {
    static char c;
    static int f;
    for (c = ch(), f = 1; c < '0' || c > '9'; c = ch())
        if (c == '-') f = -f;
    for (x = 0; c >= '0' && c <= '9'; c = ch()) x = x * 10 + (c & 15);
    x *= f;
}
template <typename T>
void write(T x) {
    static char q[65];
    int cnt = 0;
    if (x < 0) pc('-'), x = -x;
    q[++cnt] = x % 10, x /= 10;
    while (x) q[++cnt] = x % 10, x /= 10;
    while (cnt) pc(q[cnt--] + '0');
}

const int N = 2130;
int _, n;
int f[N][N];
struct node {
    int h, t;
    bool operator<(const node &a) const { return a.h < h; }
} a[N];
void solve() {
    read(_);  // memset(f,0x3f,sizeof f);
    while (_--) {
        read(n);
        int sum = 0;
        // memset(f, 0x3f, sizeof f);
        int sums = 0;
        f[0][0] = 0;
        rep(i, 1, n) {
            int x, y;
            read(x);
            read(y);
            sums += y;
            a[i].h = x;
            a[i].t = y;
        }
        memset(f,0x3f,sizeof f);
        f[0][0] = 0;
        sort(a + 1, a + 1 + n);
        int ans = 99999999;
        rep(i, 2, n) {  // printf("%d\n",a[i].h);
            //sum += a[i].t;
            bep(j, sums, 0) {
                for (int k = sums; k >= 0; --k) {
                    //int &res = f[j][k];
                    if(f[j][k] == 0x3f3f3f3f or j+k > sums)continue;
                    f[j + a[i].t][k] = min(f[j + a[i].t][k],
                                           f[j][k] + (j == 0 ? a[i].h : 0));
                    f[j][k + a[i].t] = min(
                        f[j][k + a[i].t], f[j][k] + (k == 0 ? a[i].h : 0));
                    //res = 0x3f3f3f3f;
                    // if (j - a[i].t >= 0)
                    //     res = min(
                    //         res, f[j - a[i].t][k] + (j == a[i].t ? a[i].h : 0));
                    // if (k - a[i].t >= 0)
                    //     res = min(
                    //         res, f[j][k - a[i].t] + (k == a[i].t ? a[i].h : 0));
                    // res = min(res,
                    //           f[j][k] + (sum - (j + k) == a[i].t ? a[i].h : 0));
                }
            }
            sum += a[i].t;
        }
        rep(i, 1, sums) {
            rep(j, 1, sums) {
                if (f[i][j] >= 0x3f3f3f3f or i + j >= sums) continue;
                // printf("{%d %d %d} %d %d %d\n",i,j,sum-i-j,f[n][i][j],
                // max({i,j,sum-i-j}),f[n][i][j] * max({i,j,sum-i-j}));
                ans = min((f[i][j] + a[1].h) * max(max(i, j), sums - i - j), ans);
                // f[0][i][j] = f[1][i][j] = 0x3f3f3f3f;
            }
        }
        write(ans);
        pc('\n');
    }
}
signed main(int argc, char const *argv[]) {
    solve();
    return 0;
}


posted @ 2021-10-22 20:13  xiaodangao  阅读(25)  评论(0编辑  收藏  举报