zcmu5142: 巴比伦塔

题目链接:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=5142

题目大意

搭积木。n种积木,每种长宽高给定,数量不限。一个积木a能搭在另一个积木b上的条件是b底的长宽都严格大于a底的长宽。然后问你搭积木的高度最大值。

思路

每种积木经过旋转一共有三种情况,就是三个不同底,假设ai是积木底的宽,bi是积木底的长(ai<=bi),所以将这n种积木分成3*n个积木底,高是ci,那struct存。

然后按照先ai升序,后bi升序对这3*n个数据排序,保证了后面的积木不能搭在前面的积木上。

那么接下来就类似最长上升子序列的操作。dp[i]表示1到第i块积木作为底座可以搭的最大高度,初始化为ci然后在 i之前找积木j搭,如果满足积木i长宽严格大于积木j,那么dp[i]=max(dp[i], dp[j]+ci)。最后更新dp[i]的最大值,毕竟最高的情况底座不一定是最后一块。代码中我用了vector动态数组,比较方便记录数据。

ac代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
    int a, b; //积木底的宽和长
    int height; //积木的高
    bool operator < (const node &o) const{
        if(a != o.a) return a < o.a;
        else if(b != o.b) return b < o.b;
        return height < o.height;
    }
};
int dp[105];
int main(){
    int t, cas = 1; scanf("%d", &t);
    while(t --){
        vector<node> v;
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i ++){
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            int ta, tb;
            //3种底存vector
            ta = a; tb = b;
            if(ta > tb) swap(ta, tb);
            v.push_back({ta, tb, c});
            ta = a; tb = c;
            if(ta > tb) swap(ta, tb);
            v.push_back({ta, tb, b});
            ta = b; tb = c;
            if(ta > tb) swap(ta, tb);
            v.push_back({ta, tb, a});
        }
        printf("Case %d: maximum height = ", cas ++);
        sort(v.begin(), v.end()); //排序
        int len = v.size(), ans = 0;
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i < len; i ++){
            dp[i] = v[i].height; //初始化
            for(int j = 0; j < i; j ++){
                if(v[i].a > v[j].a && v[i].b > v[j].b){ //满足搭积木条件
                    dp[i] = max(dp[i], dp[j] + v[i].height); //更新第i块积木作为底座的最大值
                }
            }
            ans = max(ans, dp[i]); //更新答案
        }
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/113406335
今日推荐