poj3124 The Bookcase

来源:互联网 发布:骂淘宝客服歹毒的话 编辑:程序博客网 时间:2024/05/16 03:48

Description 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. Tomfinds 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 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.

先按高度从大到小排序,这样每一层第一个放进去的书就是最大高度。
规定第一本书放在第一层里,用dp[i][j][k]表示前i本书,第二层宽j,第三层宽k,二三层高度的和(的最小值)。枚举每一本书放在哪里,不难得出状态转移方程。
时限卡得比较紧,注意一些常数优化。
状态的表示非常巧妙。因为宽度比较小,高度比较大,所以选择宽度作为维度,高度作为储存的值。按高度排序以后,第一层放最高的书,高度就已经定了,不用再计算。而知道了二三层的宽度和,也可以算出第一层的宽度。而且更新的时候,因为存的是最大值的和,实际上已经丢失了一部分信息,如果高度是乱序的,就没有办法计算出新的高度和。然而高度是有序的,就只用在高度第一次加入时统计。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longconst int oo=0x3f3f3f3f;struct book{    int h,w;    bool operator < (const book & bb) const    {        return h>bb.h;    }}a[75];int dp[2][2110][2110],s_w[75],n;void upd(int &x,int y){    if (y<x) x=y;}void init(){    int i;    scanf("%d",&n);    for (i=1;i<=n;i++)      scanf("%d%d",&a[i].h,&a[i].w);    sort(a+1,a+n+1);    s_w[0]=0;    for (i=1;i<=n;i++)      s_w[i]=s_w[i-1]+a[i].w;}void solve(){    int i,j,k,ans=oo;    for (j=0;j<=s_w[1];j++)      for (k=0;j+k<=s_w[1];k++)        dp[1][j][k]=oo;    dp[1][0][0]=0;    for (i=1;i<n;i++)    {        for (j=0;j<=s_w[i+1];j++)          for (k=0;j+k<=s_w[i+1];k++)            dp[i&1^1][j][k]=oo;        for (j=0;j<=s_w[i];j++)          for (k=0;j+k<=s_w[i];k++)          {            upd(dp[i&1^1][j][k],dp[i&1][j][k]);            upd(dp[i&1^1][j+a[i+1].w][k],dp[i&1][j][k]+(j?0:a[i+1].h));            upd(dp[i&1^1][j][k+a[i+1].w],dp[i&1][j][k]+(k?0:a[i+1].h));          }    }    for (j=1;j<s_w[n];j++)      for (k=1;j+k<s_w[n];k++)        if (dp[n&1][j][k]<oo)          upd(ans,(dp[n&1][j][k]+a[1].h)*max(max(j,k),s_w[n]-j-k));    printf("%d\n",ans);}int main(){    int T;    scanf("%d",&T);    while (T--)    {        init();        solve();    }}
0 0