POJ3124.The Bookcase(題解)
阿新 • • 發佈:2021-10-22
思路:我們發現一共需要求兩維東西,一個是寬度,另一個是高度,那麼依據我們的經驗,可以將高度首先進行一次排序。那麼是由高到低排好,還是由低到高排好呢?
- 考慮由低到高,顯然每一次加入一個東西\(i\)時,該東西一定是最高的,該東西加入的那一排,高度一定是\(h[i]\),但是有一個問題是我們還需要知道其他兩維的高度,那麼我們必須再開兩維陣列來表示,顯然解決了一部分問題,但是並不能完全解決問題。
- 考慮由高到低,由高到低一個最大的好處就是,這三排中的\(Max_high\)一定在頭部,此時我們如果用陣列來表示寬度的話,那麼如果寬度不為0,就代表這一排前面一定有比這個高的,高度不會改變,所以我們能夠用一維來表示兩維能表示的東西,很好的解決了這個問題。
因為我們需要求最小面積 = \(\sum Max\_high * \sum Max\_width\)
\(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\)轉移,那麼一個顯而易見的想法是開滾動陣列(然而我還是過不了
\(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; }