现在的位置: 首页 > 综合 > 正文

UVA 12099 – The Bookcase(dp+状态剪枝)

2019年04月04日 ⁄ 综合 ⁄ 共 1482字 ⁄ 字号 评论关闭

本题采用了dp+加状态剪枝的策略;

第一点,必须明确,最优子结构为前面 i 本书的最佳放法是由 前 i-1本书的最佳方法的基础上加上第 i 本书组合而来;

d[i ][j ][k ] 代表已经安置 前 i本书,第二层宽度为j,第三层宽度为k ,且第二层高>=第三层高度,最高的那本书放在第一层时的 第二层和第三层的最小高度和;

该状态是在每层厚度一定情况下的最优解;

这样一来最终解要遍历i = n的所有状态求最优;

由于d[i ][j ][k ] 并不能明显的找出其所依赖的子结构,但用它来更新i+1的状态却比较容易转移,所以采用刷表法

还有状态太大需要剪剪枝,见代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 2110000
#define Inf 1000
const int maxn = 71;
const int maxm = 2105;
int d[maxn][maxm][maxm],n,maxw=30,sumw[maxn];
struct Book{
int H,W;
bool operator < (const Book& rhs)const{
return H>rhs.H;
}
}a[maxn];
int f(int i,int j){
return i==0 ? j : 0;
}
long long dp(){
int lim=n*maxw;
for(int i=1;i<=n;i++){
      for(int j=0;j<=lim;j++)
         for(int k=0;k<=lim;k++){
              if(j+k>sumw[i]-a[1].W || sumw[i]-j-k + 30 < j || j + 30 < k) break;
              d[i][j][k]=Inf;
      }
}
d[1][0][0]=0;
int ans = INF;
for(int i=1;i<n;i++){
      for(int j=0;j<=lim;j++)
         for(int k=0;k<=lim;k++){
              if(j+k>sumw[i]-a[1].W || sumw[i]-j-k + 30 < j || j + 30 < k) break;
              d[i+1][j][k]=min(d[i+1][j][k],d[i][j][k]);
              d[i+1][j+a[i+1].W][k] = min(d[i+1][j+a[i+1].W][k],d[i][j][k] + f(j,a[i+1].H));
              if(j>0)
              d[i+1][j][k+a[i+1].W] = min(d[i+1][j][k+a[i+1].W],d[i][j][k] + f(k,a[i+1].H));
         }
}
for(int j=0;j<=lim;j++)
         for(int k=0;k<=lim;k++){
              if(j+k>sumw[n]-a[1].W || sumw[n]-j-k + 30 < j || j + 30 < k) break;
              if(d[n][j][k]!=INF&&j>0&&k>0){
              ans = min(ans,(d[n][j][k]+a[1].H)*(max(sumw[n]-j-k,max(j,k))));
              }
}
return ans;
}
int main()
{
  int T;
  scanf("%d",&T);
   while(T--){
          scanf("%d",&n);
          for(int i=1;i<=n;i++) scanf("%d %d",&a[i].H,&a[i].W);
          sort(a+1,a+1+n);
          sumw[0]=0;
          for(int i=1;i<=n;i++){
                 sumw[i]=a[i].W+sumw[i-1];
          }
          printf("%d\n",dp());
   }
   return 0;
}

抱歉!评论已关闭.