Leo搭积木【DP】

家住魔仙堡 提交于 2019-11-28 08:13:00

>Description
有n种积木,积木能无限供应。每种积木都是长方体,第i种积木的长、宽、高分别为li、wi、hi。积木可以旋转,使得长宽高任意变换。Leo想要用这些积木搭一个最高的塔。问题是,如果要把一个积木放在另一个积木上面,必须保证上面积木的长和宽都严格小于下面积木的长和宽。这意味着,即使两块长宽相同的积木也不能堆起来。
给出积木,求最高能达到多少。


>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

对于30%的数据 n<=8
对于100%的数据 n<=3000,最后答案不会超过32位整型


>解题思路
我傻了这明明是一道简单DP我竟然比赛时没做出来

因为长方体可以旋转,所以一个长方体有三种方式摆放(要维护长长于宽)
求最长不下降序列的模板,首先得根据长从大到小排列所有的长方体,所有的f[i]f[i]表示选第ii个长方体的最高高度,每次计算时直接枚举11 ~ i1i-1之间的长方体,如果可以放上去的话就计算

状态转移方程:f[i]=max(f[i],f[j]+h[i])f[i]=max(f[i],f[j]+h[i])


>代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

struct brick
{
	int l, w, h;
}a[9010];
int n, t, ans, f[9010];

bool cmp (brick aa, brick bb) {return aa.l > bb.l;}
int main()
{
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		t++;
		scanf ("%d%d%d", &a[t].l, &a[t].w, &a[t].h);
		
		a[++t] = (brick) {a[t - 1].l, a[t - 1].h, a[t - 1].w};
		a[++t] = (brick) {a[t - 2].w, a[t - 2].h, a[t - 2].l};
	}
	for (int i = 1; i <= t; i++)
	 if (a[i].l < a[i].w) swap (a[i].l, a[i].w); //长一定长于宽
	 
	sort (a + 1, a + 1 + t, cmp);
	for (int i = 1; i <= t; i++)
	{
		f[i] = a[i].h;
		for (int j = 1; j < i; j++)
	     if (a[j].l > a[i].l && a[j].w > a[i].w) //判断是否可以放上去
	      f[i] = max (f[i], f[j] + a[i].h);
	    ans = max (ans, f[i]);
	}
	printf ("%d", ans);
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!