题目链接: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;
}