UVa 12099 The Bookcase (DP)

题意:有 n 本书,每本书有一个高度和宽度,然后让你制作一个3层的书架,可以放下所有的书,并且要高*宽尽量小。

析:先把所有的书按高度进行排序,然后dp[i][j][k] 表示 前 i 本书,第二 层的宽度是 j,第三层的宽度是 k,第二层和第三层的高度最小,首先我们可以先最高的那本书放到第一层,那么这一层的高度就确定了,同理,在放第二层和第三层的时候,如果是第一本书,那么这一层的高度就已经确定了,为什么不表示第一层的宽度呢,因为总宽度是确定的,如果第二层的宽度和第三层的宽度知道了,那么第一层也就确定了。有了这些就可以进行状态转移了。注意不要转移无用的状态以降低时间复杂度。

有三种决策,1 放在第一层,dp[i+1][j][k] = min{ dp[i][j][k] }

2.放在第二层,那么又有两种情况,第一次放,还是不是第一次放

if(j == 0)  dp[i+1][j+w][k] = min{ dp[i][j][k] + h }

else  dp[i+1][j+w][k] = min{ dp[i][j][k] }

3.放在第三层,这一种和第二层一样。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#define debug() puts("++++");
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define pu push_up
#define pd push_down
#define cl clear()
#define all 1,n,1
#define FOR(x,n)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 200000 + 10;
const LL mod = 1e9 + 7;
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
  return r > 0 && r <= n && c > 0 && c <= m;
}

int dp[2][2105][2105];
struct Node{
  int h, w;
  bool operator < (const Node &p) const {
    return h > p.h;
  }
};
Node a[80];
int sum[maxn];

int main(){
  int T;  cin >> 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 + n + 1);
    for(int i = 2; i <= n; ++i)  sum[i] = sum[i-1] + a[i].w;
    int cnt = 0;
    ms(dp[0], INF);
    dp[0][0][0] = 0;
    for(int i = 1; i < n; ++i, cnt ^= 1){
      ms(dp[cnt^1], INF);
      for(int j = 0; j <= sum[i]; ++j){
        for(int k = 0; k <= sum[i]; ++k){
          if(j + k > sum[i])  break;
          if(dp[cnt][j][k] == INF)  continue;
          dp[cnt^1][j][k] = min(dp[cnt^1][j][k], dp[cnt][j][k]);
          if(j == 0)  dp[cnt^1][a[i+1].w][k] = min(dp[cnt^1][a[i+1].w][k], dp[cnt][j][k] + a[i+1].h);
          else dp[cnt^1][j+a[i+1].w][k] = min(dp[cnt^1][j+a[i+1].w][k], dp[cnt][j][k]);
          if(k == 0)  dp[cnt^1][j][a[i+1].w] = min(dp[cnt^1][j][a[i+1].w], dp[cnt][j][k] + a[i+1].h);
          else dp[cnt^1][j][k+a[i+1].w] = min(dp[cnt^1][j][k+a[i+1].w], dp[cnt][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[cnt][i][j] == INF)  continue;
        if(i == 0 || j == 0)  continue;
        ans = min(ans, (dp[cnt][i][j] + a[1].h) * max(j, max(i, sum[n]-j-i+a[1].w)));
      }
    printf("%d\n", ans);
  }
  return 0;
}

  

时间: 2024-07-30 13:52:27

UVa 12099 The Bookcase (DP)的相关文章

UVa 12099 The Bookcase - 动态规划

题目大意 给定一些书,每个书有一个高度和宽度,然后将它们放到一个三层的书架里(要求每一层都不为空).定义书架的大小为每层最大的高度和 乘 每层宽度和的最大值.求最小的书架大小. 显然动态规划(直觉,没有为什么). 然后确定状态,f[i][j][k]表示正在考虑第i本书,第2层的宽度和为j,第3层的宽度和为k(这样第一层的宽度和就可以计算出来)最小的高度和.然后发现无处下手...难道要把所有高度记录下来? 现在来考虑优化,最简单的一种就是去除无用.重复状态. step 1 >> 放书的顺序和结果

UVA - 12099 The Bookcase

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.

【暑假】[深入动态规划]UVa 10618 The Bookcase

UVa 12099  The Bookcase 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=42067 思路:   将n本书分配到三层,使得形成的书架w*h最小 提前将书籍按照高度排序,因为无论第一本书(最高的书)无论放在那一层都会被考虑到,所以规定将它放在第一层,且第二层比第三层高. 因为从大到小排序的关系,只要jk==0那么新加入的书i就是该层的高度,否则高度不变. 设d[i][j][k]表示考虑过i本书第二

[UVA 12589]Learning Vector[DP]

题目链接:[UVA 12589]Learning Vector[DP] 题意分析:给出n个矢量,从中选择k个,以坐标原点为起点,收尾相连,问:这样的k个周围相连矢量与x轴围成图形的最大面积的两倍是多少? 解题思路:考虑状态:dp[id][pick][h]代表到第id个矢量为止,选择pick个矢量离最大面积还差多少,h为当前图形最右端高度.具体转移看代码. 这里着重说一下为什么要对这些矢量按斜率进行排序: 首先,整个求解过程其实就是在暴力枚举这些向量的组合,只不过采用了记忆化搜索优化. 其次,对于

Uva 12018 Juice Extractor dp

题目链接:点击打开链接 题意: 切水果游戏 给出n个水果 水果出现在屏幕上的时间的区间 1.每次切会把屏幕上所有水果切完 2.当同时切3个或以上时计分,分数为切的水果个数 3.不能遗漏水果 问最高得分 dp[i] 表示 最后一次切第i个的得分. #include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> using namespace std; #define N 1

uva 11578 - Situp Benches(dp+输出路径)

题目连接:uva 11578 - Situp Benches 题目大意:健身房有两个仪器,初始角度为10度,每次有人使用需要交15元,每调10度需要花费10元,现在有n个人,给出每个人使用仪器的顺序和角度,保证不会同时有大于2个人序号一样,求最小花费,并且输出每个人分别使用哪一个仪器,并且所有人使用结束后,要将仪器调回10度. 解题思路:dp[i][x][y]表示第i个人,一个仪器为x,另一个仪器为y的情况,path[i][x][y]记录的是它的前一个状态,[0]为前一个仪器的夹角,[1]为另一

uva 10269 最短路+dp

题意:有a个村庄.b个城镇, 编号分别为:1-a , a+1--a+b . 有双神奇的鞋,可以瞬时移动,可以使用k次,每次可以移动L , 但穿这双鞋的时候,不能经过城镇 , 问:从a+b 到 1 最短距离是多少? 刚开始看这个题时 , 一点思路都没有 , dp类型的题目做得太少了. 解法:进行状态压缩, 用点+使用鞋子的次数 , 来表示一个状态 , d[i][k] , 表示到 点 i 使用 k 次鞋子的最短距离是多少. 但要先进行初始化 , 求任意点之间不经过城镇的最短距离 , 用floyd算法

uva 10671 - Grid Speed(dp)

题目链接:uva 10671 - Grid Speed 题目大意:给出N,表示在一个N*N的网格中,每段路长L,现在给出h,v的限制速度,以及起始位置sx,sy,终止位置ex,ey,时间范围st,et,车只走最短路,问说在范围内最快到达和耗油量最小的情况下时间和耗油量. 解题思路:dp[x][y][t]表示在x,y这一点,时间为t的耗油量最小为dp[x][y][t],vis[x][y][t]表示该情况是否可达.dx,dy表示由起点向终点移动的方向.因为时间为L?60v, 因为v是5的倍数,并且小

UVA 1559 - Nim(博弈dp)

UVA 1559 - Nim 题目链接 题意:一开始有s个石子,2n个人轮流取石子,每个人有个最大能取数目,2n个人奇数一队,偶数一队,取到最后一个石子的队输,问谁赢 思路:记忆化搜索,每个人取的时候对应的后继状态如果有一个必败态,则该状态为必胜态,如果都是必胜态,则该状态为必败态 代码: #include <stdio.h> #include <string.h> int n, s, m[25], dp[25][10005]; int dfs(int now, int state