1. 程式人生 > >UVA - 12099 The Bookcase

UVA - 12099 The Bookcase

struct uva new oss cap ets 最小值 構造 ast

No wonder the old bookcase caved under the massive piles of books Tom had stacked on it. He had better build a new one, this time large enough to hold all of his books. Tom finds it practical to have the books close at hand when he works at his desk. Therefore, he is imagining a compact solution with the bookcase standing on the back of the desk. Obviously, this would put some restrictions on the size of the bookcase, it should preferably be as small as possible. In addition, Tom would like the bookcase to have exactly three shelves for aesthetical reasons. Wondering how small his bookcase could be, he models the problem as follows. He measures the height hi and thickness ti of each book i and he seeks a partition of the books in three non-empty sets S1, S2, S3 such that (∑3 j=1 maxi∈Sj hi) × (max3 j=1 ∑ i∈Sj ti) is minimized, i.e. the area of the bookcase as seen when standing in front of it (the depth needed is obviously the largest width of all his books, regardless of the partition). Note that this formula does not give the exact area of the bookcase, since the actual shelves cause a small additional height, and the sides cause a small additional width. For simplicity, we will ignore this small discrepancy. Thinking a moment on the problem, Tom realizes he will need a computer program to do the job

Input

The input begins with a positive number on a line of its own telling the number of test cases (at most 20). For each test case there is one line containing a single positive integer N, 3 ≤ N ≤ 70 giving the number of books. Then N lines follow each containing two positive integers hi , ti , satisfying 150 ≤ hi ≤ 300 and 5 ≤ ti ≤ 30, the height and thickness of book i respectively, in millimeters.

Output

For each test case, output one line containing the minimum area (height times width) of a three-shelf bookcase capable of holding all the books, expressed in square millimeters.

Sample Input

2

4

220 29

195 20

200 9

180 30

6

256 20

255 30

254 15

253 20

252 15

251 9

Sample Output

18000 29796

  這個題目在狀態的構造上,十分用心,如果我們考慮暴力DP那麽顯然要記下6個東西,就是每行的長和高,當然首先空間上過不去,其次,轉移也十分復雜,那麽考慮優化我們的狀態。

  首先只要記下兩個寬和一個高就可以了,因為如果我們知道兩個寬,就可以用總和減去兩個寬得到下一個寬,然後有一個高是必定不用記下的,因為他一定是最高的那本書,然後第一維記處理到那本書,可以滾動,數組裏存剩下的一個高,但即使優化到這個地步還是會暴空間!怎麽辦?

  我們把那兩個高之和的最小值存在數組了,這樣就只有三維(相當於兩維),即:設dp[i][j][k],表示dp到第i本書,第二列的寬度是j,第三列的寬度是k的二三列的最小高度和,這個為什麽可以轉移呢?我們考慮將每本書按照高度排序!那麽第一本(最高的一本)我們強制放在第一列,而且只要第二列,第三列有書,因為我們是從高到低放的所以一定更新不了最大當列的最高值,進而更新不了他們的高度和!

  轉移就是枚舉本書分放到第1,2,3,層進行轉移。

代碼:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#define MAXN 2150
#define ll long long
using namespace std;
struct book{
    int h,w;
}a[80];
int f[MAXN][MAXN],dp[2][MAXN][MAXN],sum[80];
int n,inf;

bool cmp(book x,book y){
    return x.h>y.h;
}

int main(){
    int t;cin>>t;
    while(t--){
        memset(f,0,sizeof(f));
        memset(dp,127,sizeof(dp));inf=dp[0][0][0];
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&a[i].h,&a[i].w);
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].w;
        for(int i=1;i<=n;i++){
            f[0][a[i].h]=a[i].h;
        }
        dp[0][0][0]=0;
        int now=0,last=1;
        for(int i=1;i<n;i++){
            now^=1,last^=1;
            memset(dp[now],127,sizeof(dp[now]));
            for(int j=0;j<=sum[i];j++)
                for(int k=0;k<=sum[i];k++){
                    if(dp[last][j][k]==inf) continue;
                    if(j+k>sum[i]) break;
                    dp[now][j+a[i+1].w][k]=min(dp[now][j+a[i+1].w][k],dp[last][j][k]+f[j][a[i+1].h]);
                    dp[now][j][k+a[i+1].w]=min(dp[now][j][k+a[i+1].w],dp[last][j][k]+f[k][a[i+1].h]);
                    dp[now][j][k]=min(dp[now][j][k],dp[last][j][k]);
                }
        }
        int ans=inf;
        for(int i=0;i<=sum[n];i++)
        for(int j=0;j<=sum[n];j++){
            if(i+j>sum[n]) break;
            if(dp[now][i][j]==inf) continue;
            if(i == 0 || j == 0)  continue;
            ans = min(ans, (dp[now][i][j] + a[1].h) * max(j, max(i, sum[n]-j-i)));
        }
        printf("%d\n",ans);
    }
}

UVA - 12099 The Bookcase