1. 程式人生 > 其它 >POJ3124.The Bookcase(題解)

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;
}