【DP】搭积木

还是蛮简单的(因为数据不是怎么大),但今天是颓废的一天~【滑稽】【逃

是中山纪念中学的题。。。题目链接戳


Leo是一个快乐的火星人,总是能和地球上的OIers玩得很high。
2012到了,Leo又被召回火星了,在火星上没人陪他玩了,但是他有好多好多积木,于是他开始搭积木玩。
火星人能制造n种积木,积木能无限供应。每种积木都是长方体,第i种积木的长、宽、高分别为li、wi、hi。积木可以旋转,使得长宽高任意变换。Leo想要用这些积木搭一个最高的塔。问题是,如果要把一个积木放在另一个积木上面,必须保证上面积木的长和宽都严格小于下面积木的长和宽。这意味着,即使两块长宽相同的积木也不能堆起来。
火星上没有电脑,好心的你决定帮助Leo求出最高的塔的高度。

【提示】
每种积木都可以拆分成高度分别为li、wi、hi的三种积木,另两边作为长和宽,保证长>=宽。

Input-

第一行,一个整数n,表示积木的种数
接下来n行,每行3个整数li,wi,hi,表示积木的长宽高

Output-

一行一个整数,表示塔高的最大值

Sample Input-

-Sample Input1:

1
10 20 30

-Sample Input2:

2
6 8 10
5 5 5

-Sample Input3:

5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
Sample Output-

-Sample Output1:

40

-Sample Output2:

21

-Sample Output3:

342

  1. 由于我们可以把积木旋转摆放,所以每种积木我们都可以获得3种不同的形态。
    (长宽高全排列6种,因为长必须比宽高,所以变成3种)
  2. 我们按长从大到小排序(如果长相同按宽从大到小排序),使后面可以放到前面的上。
    (形成一个不下降子序列)
  3. 然后DP.
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,ans[100001],Ans,a,b,c;
struct asdf{
	int C,K,G;  //这是长,这是宽,这是高............的首拼音
} s[100001];
bool cmp(asdf aa,asdf bb){  //按长从大到小排
	if(aa.C != bb.C) return aa.C > bb.C;  //如果长度不相同
	return aa.K > bb.K;   //长度相同按宽从大到小排
}
int main(){
	freopen("brick.in","r",stdin);
	freopen("brick.out","w",stdout);
	scanf("%d",&n);           //读入,没问题
	for(int i = 1; i <= n; ++i){
		scanf("%d%d%d",&a,&b,&c);
		s[i * 3 - 2] = (asdf) {max(a,b), min(a,b), c};   //将3种情况存到结构体里
		s[i * 3 - 1] = (asdf) {max(a,c), min(a,c), b};
		s[i * 3 - 0] = (asdf) {max(b,c), min(b,c), a};
	} 
	sort(s + 1, s + 1 + 3 * n, cmp);  //排序,如上所说
	for(int i = 1; i <= 3 * n; ++i){    //每种积木轮一遍
		for(int j = i - 1; j >= 0; --j)   //可能堆到的
		  if(s[i].C < s[j].C && s[i].K < s[j].K)   //如果摆得上去
		      ans[i] = max(ans[i],ans[j]);   //取一个最大值
		ans[i] += s[i].G;   //加上本积木的最大值
		Ans = max(Ans,ans[i]);   //Ans存一下
	}
	printf("%d",Ans);   //输出
	fclose(stdin);
	fclose(stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值