[kuangbin带你飞]专题十二 基础DP1 C - Monkey and Banana

第一次不看题解1A掉DP,虽然是简单的2333.

题意概要:

有n类箱子,每类可以无限使用,求最高用这些箱子堆成多高塔?箱子可以任意旋转和翻转

限制:
1. 塔中每个箱子的底面的长和宽都要比它下面的箱子的长和宽严格的小

思路:
1. 我首先想到的是箱子可以无限用诶,难道没有一个限制吗?然后灵光一动,一类箱子如果不旋转和翻转,就只能放一个进塔中(由限制1), 那么可以旋转和翻转就最多6个啦,如果输入的是x y z,那么这六个就是:
x y z,
y z x,
x z y,
z x y,
y z x,
z y x。
也就是x y z的排列组合啦(23333)
所以把输入按以上处理就可以把箱子的无限化为有限

2.那么如何表示状态,我想到的首先就是dp[i][j], 用了 i个箱子并且用了第j个箱子时能达到的最大高度。
状态如何转移呢?
如果第k个箱子的底面比第j个箱子大
dp[i][j] = max(dp[i][j], dp[i-1][k] + node[j].z);
node[j]表示第j个箱子,z是它的高

为了方便处理我们用x对箱子排序这样只用遍历之前的箱子,而不用遍历所有箱子。
初始化时node[0]代表地,所以x, y为INF, z 为0。
得到代码如下:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define long long ll
#define INF 0x7fffffff
using namespace std;
struct Node{
    int x, y, z;
}node[200];
int dp[200][200];

void assignTo(int i, int x, int y, int z){
    node[i].x = x;
    node[i].y = y;
    node[i].z = z;
}
bool cmp(Node a, Node b){
    return a.x > b.x;
}
int main(){
    #ifdef _LOCAL_
    freopen("C:\\Users\\Sorie\\Desktop\\debug\\in.txt","r",stdin);
    freopen("C:\\Users\\Sorie\\Desktop\\debug\\out.txt","w",stdout);
    #endif
    int n;
    int kase = 1;
    while(cin >> n && n){
        int cnt = 0;
        int x, y, z;
        node[0].x = node[0].y = INF;
        node[0].z = 0;
        memset(dp, 0 , sizeof dp);
        for(int i = 1; i <=n ; i++){
            scanf("%d %d %d", &x, &y, &z);
            assignTo(++cnt, x, y, z);
            assignTo(++cnt, y, x, z);
            assignTo(++cnt, x, z, y);
            assignTo(++cnt, z, x, y);
            assignTo(++cnt, y, z, x);
            assignTo(++cnt, z, y, x);
        }

        sort(node + 1, node + cnt + 1, cmp);
        int ans = 0;
        for(int i = 1; i <= cnt; i++){
            for(int j = i; j <= cnt; j++){
                for(int k = i - 1; k <= j; k++){
                    if(node[j].x < node[k].x && node[j].y < node[k].y){
                        dp[i][j] = max(dp[i-1][k]+node[j].z, dp[i][j]);
                        ans = max(ans, dp[i][j]);
                    }
                }
            }
        }
        cout << "Case " << kase++ << ": maximum height = ";
        cout << ans << endl;
    }
    return 0;
}

我们可以发现,每次只用了前一个状态,所以可以把dp降成一维

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define long long ll
#define INF 0x7fffffff
using namespace std;
struct Node{
    int x, y, z;
}node[200];
int dp[200];

void assignTo(int i, int x, int y, int z){
    node[i].x = x;
    node[i].y = y;
    node[i].z = z;
}
bool cmp(Node a, Node b){
    return a.x > b.x;
}
int main(){
    #ifdef _LOCAL_
    freopen("C:\\Users\\Sorie\\Desktop\\debug\\in.txt","r",stdin);
    freopen("C:\\Users\\Sorie\\Desktop\\debug\\out.txt","w",stdout);
    #endif
    int n;
    int kase = 1;
    while(cin >> n && n){
        int cnt = 0;
        int x, y, z;
        node[0].x = node[0].y = INF;
        node[0].z = 0;
        memset(dp, 0 , sizeof dp);
        for(int i = 1; i <=n ; i++){
            scanf("%d %d %d", &x, &y, &z);
            assignTo(++cnt, x, y, z);
            assignTo(++cnt, y, x, z);
            assignTo(++cnt, x, z, y);
            assignTo(++cnt, z, x, y);
            assignTo(++cnt, y, z, x);
            assignTo(++cnt, z, y, x);
        }

        sort(node + 1, node + cnt + 1, cmp);
        int ans = 0;
        for(int i = 1; i <= cnt; i++){
            for(int j = i; j <= cnt; j++){
                for(int k = i - 1; k < j; k++){
                    if(node[j].x < node[k].x && node[j].y < node[k].y){
                        dp[j] = max(dp[k]+node[j].z, dp[j]);
                        ans = max(ans, dp[j]);
                    }
                }
            }
        }
        cout << "Case " << kase++ << ": maximum height = ";
        cout << ans << endl;
    }
    return 0;
}

欢迎指正, 以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值