您的位置:首页 > 其它

12099 - The Bookcase

2015-07-17 14:40 337 查看
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 nds 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 maxi2Sjhi) 

(max3

j=1Σi2Sj

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(i,j,k)为已处理i本书,在第二层上书的总宽度为j,第三层书的总宽度为k时。第二三两层书的最小总高度。其实我们已经知道三层书的总宽度为dp(i,j,k)+h[0].,所有书的宽度是一定的,那么第一层的宽度为

转移策略无非有三:

一、放在第一层。那么dp(i,j,k)可以向dp(i,j,k)转移;

二、放在第二层。那么dp(i+1,j+w[i],k)=min{dp(i+1,j+w[i],k),dp(i,j,k)+f(j,h[i])转移。f(j,h[i])当j=0时为h[i]否则为0;

三、放在第三层。大致和二类似。

另外的。还有优化,否则状态总数70*2100*2100难以让人接受。

滚动数组,缩小空间。

优化1.注意到j+k应不大于前i本书的总宽度。

优化2.如果以ww1代表第一层总宽度。如果ww1+30 < ww2,30是一本书最大宽度。那么完全可以把第二层的一本书移到第一层。宽度肯定不会增加。换一句话说。我们只要解决满足ww2+30<=ww1;ww3+30<=ww2的状态就可以了。

优化1:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn=70+5;
const int maxw=30;
const int INF=1000000000;
struct Book{
int h,w;
bool operator < (const Book& rhs)const{
return h>rhs.h||(h==rhs.h&&w>rhs.w);
}
}books[maxn];
int n,dp[2][maxn*maxw][maxn*maxw],sumw[maxn];
inline int f(int w,int h)
{
return w==0?h:0;
}
inline void update(int& newd,int d)
{
if(newd<0||newd>d)newd=d;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&books[i].h,&books[i].w);
}
sort(books,books+n);
sumw[0]=0;
for(int i=1;i<=n;i++)
sumw[i]=sumw[i-1]+books[i-1].w;
dp[0][0][0]=0;
int t=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<=sumw[i+1];j++)
for(int k=0;k<=sumw[i+1]-j;k++)
dp[t^1][j][k]=-1;
for(int j=0;j<=sumw[i];j++)
{
for(int k=0;k<=sumw[i]-j;k++)
if(dp[t][j][k]>=0){
update(dp[t^1][j][k],dp[t][j][k]);
update(dp[t^1][j+books[i].w][k],dp[t][j][k]+f(j,books[i].h));
update(dp[t^1][j][k+books[i].w],dp[t][j][k]+f(k,books[i].h));
}
}
t^=1;
}
int ans=INF;
for(int j=1;j<=sumw
;j++)//每层至少有一本书,因为最少是三本,排序后,最高的放在第一层,那么,每层都放肯定是最优的。所以宽度一定不为0
{
for(int k=1;k<=sumw
-j;k++)
{
if(dp[t][j][k]>=0){
int w=max(max(j,k),sumw
-j-k);
int h=dp[t][j][k]+books[0].h;
ans=min(ans,w*h);
}
}
}
printf("%d\n",ans);
}
return 0;
}


优化1,2:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn=70+5;
const int maxw=30;
const int INF=1000000000;
struct Book{
int h,w;
bool operator < (const Book& rhs)const{
return h>rhs.h||(h==rhs.h&&w>rhs.w);
}
}bo
c5fd
oks[maxn];
int n,dp[2][maxn*maxw][maxn*maxw],sumw[maxn];
inline int f(int w,int h)
{
return w==0?h:0;
}
inline void update(int& newd,int d)
{
if(newd<0||newd>d)newd=d;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&books[i].h,&books[i].w);
}
sort(books,books+n);
sumw[0]=0;
for(int i=1;i<=n;i++)
sumw[i]=sumw[i-1]+books[i-1].w;
dp[0][0][0]=0;
int t=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<=sumw[i+1];j++)
for(int k=0;k<=sumw[i+1]-j;k++)
dp[t^1][j][k]=-1;
for(int j=0;j<=sumw[i];j++)
{
for(int k=0;k<=sumw[i]-j;k++)
{
if(k>j+30||j>sumw
-j-k+30)continue;
if(dp[t][j][k]>=0){
update(dp[t^1][j][k],dp[t][j][k]);
update(dp[t^1][j+books[i].w][k],dp[t][j][k]+f(j,books[i].h));
update(dp[t^1][j][k+books[i].w],dp[t][j][k]+f(k,books[i].h));
}
}

}
t^=1;
}
int ans=INF;
for(int j=1;j<=sumw
;j++)//每层至少有一本书,因为最少是三本,排序后,最高的放在第一层,那么,每层都放肯定是最优的。所以宽度一定不为0
{
for(int k=1;k<=sumw
-j;k++)
{
if(k>j+30||j>sumw
-j-k+30)continue;
if(dp[t][j][k]>=0){
int w=max(max(j,k),sumw
-j-k);
int h=dp[t][j][k]+books[0].h;
ans=min(ans,w*h);
}
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: