HDU1069Monkey and banana Uva437 The Tower of Babylon(动态规划)

题目大意:

有n中长方体,每种都有无穷多个。要求选一些长方体搭成尽量高的柱子,使得每个长方体底面的长宽严格小于它下方的长方体(长的跟金字塔差不多)。注意不是小等于!!并且一个长方体有三个参数,每个参数都可以当做是高。

题目解析:

这是最优子结构问题,从一开始就要考虑如何塔的最高。在任何时候只有当前顶面的尺寸会影响到接下来的决策。因此可以用一个二维数组d(i,j)表示当前顶面的长和宽。但因为长和宽可能会非常的大,导致数组开不下,所以我们要间接表示这个状态。
从问题分析,我们发现一个长方体的高有三种可能,也就是说可以把一个长方体分成三种形态。如果我们一开始就用一个二维数组block[i][k]存取第i个长方体的三个参数,那么我们可以用d(idx,j)来表示第idx个长方体的第j种形态,而长宽就对应r[i]中除了第j个元素的另外两个元素。这样数组的大小大大减小。
状态总数是O(n)个,决策也是O(n)个,时间复杂度为O(n^2)。

状态转移方程:

d(i)(j) = max(d(i)(j) , block[i][j] + dp(x,y))。
因为递推太复杂,所以采用记忆化搜索的方法。

代码:

#include <set>
#include <numeric>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <string>
#include <sstream>
#include <map>
#include <functional>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
#define REP(idx1,num1) for(int idx1=0;idx1<(num1);idx1++)
#define pb push_back
#define empb emplace_back
#define mp make_pair
#define mem(s) memset(s,0,sizeof(s));
const double EPS = 1e-6;
//const int maxn = 280;
int d[33][5];
int n;
int block[33][4];
void get_b(int *v,int i,int h)//获取长宽
{
    int ptr = 0;
    for(int j = 0; j < 3; ++j)
        if(j != h)
            v[ptr++] = block[i][j];
}
int dp(int x,int y)
{
    if(d[x][y] > 0) return d[x][y];
    d[x][y] = block[x][y];//初始化。
    int v1[2];//当前顶面的长宽
    get_b(v1,x,y);
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < 3; ++j)
        {
            int v[2];//将要塔的长方体的长宽
            get_b(v,i,j);
            if(v[0] < v1[0] && v[1] < v1[1])
                d[x][y] = max(d[x][y], block[x][y]+dp(i,j));
            else if(v[1] < v1[0] && v[0] < v1[1])
                d[x][y] = max(d[x][y], block[x][y]+dp(i,j));
        }
    return d[x][y];
}
int main()
{
    int kase = 1;
    while(cin >> n && n){
        mem(d);
        for(int i = 0; i < n; ++i){
            for(int j = 0; j < 3; ++j)
                cin >> block[i][j];
            //sort(block[i],block[i]+3);
            //如果这里进行排序的话上面的状态转移方程就可以少写一个。
        }
        //枚举所有的长方体
        int tallest = -1;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < 3; ++j)
                tallest = max(tallest,dp(i,j));
        printf("Case %d: maximum height = %d\n",kase++,tallest);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值