我承认,这道题我做了很久,大概是三天吧……所以应该把这道题答案放出来……
啃动态规划嘛,那肯定就是动态规划啦!
题目大意是有N种木块,每种无限个,有长宽高,任意两个当底,一个当高,把这些木块摞起来,上面的木块长和宽都必须比下面的小,问最高能摞多高?
好 吧,这道题刚开始看到的时候我果断看成了一个无限空间的背包问题,但是马上我就发现了bug,如果真的是当背包做,第二重循环怎么写啊……然后开始枚举第 二个状态……f[i]表示当第i个木块为顶时的最高高度,每一个木块都得比它下面的木块小,仔仔细细想想就能发现一个木块只能用三个,那么好吧,存储的时 候一个当成三个存好了……
遇到这种情况我喜欢用结构体,因为这样一个变量就可以存入一个木块的所有的参数,果断就是组合数,长宽高就那么存 就行了,而且长永远比宽长,为了保险,以所有木块的长为主进行排序。然后开始做,第i个木块为顶,然后开始扫它底下的木块,因为事先排过序了,在i下面的 木块只能是i之前的而且宽比i小的木块(实际上,愿意扫全场也行)。
最优子结构是当第i个为顶为最高的时候,i的下面一定存在一点k,当第 k个木块在最顶上的时候,使得高度最高,然后以k为最底,当第i个木块在最顶上的时候,使得高度最高,这样一来整体高度最高。说实话,我想过当摞了前i个 木块,使得高度最高的子结构,结果我就发现了每个木块都有三种摆放方式,然后就是一个大bug——根本无法实现好不好……
最优子结构找到了,然后就是写方程了哈
方程那段的代码:
if (f[i] < f[j] + a[i].g) f[i] = f[j] + a[i].g;
a[i].g是第i个的高,j表示的是i下面的那个,每一步都要有一个初始化,就是f[i] = a[i].g。
好了……写完了。
PS:其实这个灵感来自于磊哥的一个指导……原版是f[i, s]表示当第i个以s方式为顶的时候,最高的高度,然后我觉得木块的变化有点高深,就干脆把一个木块当成三个木块了。。。
特别鸣谢:磊哥ZLGG
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct data
{
int x, y, z;
}a[100];
int n, i, j, tot, x, y, z, dp[100];
int max(int a, int b)
{
if (a > b) return a;
else return b;
}
int min(int a, int b)
{
if (a < b) return a;
else return b;
}
int cmp(data a, data b)
{
return a.x > b.x;
}
void add(int x, int y, int z)
{
tot++;
a[tot].x = max(x, y);
a[tot].y = min(x, y);
a[tot].z = z;
tot++;
a[tot].x = max(x, z);
a[tot].y = min(x, z);
a[tot].z = y;
tot++;
a[tot].x = max(y, z);
a[tot].y = min(y, z);
a[tot].z = x;
}
int main()
{
int t = 1;
while (cin >> n && n != 0)
{
tot = 0;
memset(dp, 0, sizeof(dp));
for (i = 1; i <= n; i++)
{
cin >> x >> y >> z;
add(x, y, z);
}
sort(a + 1, a + tot + 1, cmp);
for (i = 1; i <= tot; i++) dp[i] = a[i].z;
for (i = 2; i <= tot; i++)
for (j = 1; j <= i; j++)
{
if (a[j].x > a[i].x && a[j].y > a[i].y)
{
dp[i] = max(dp[i], dp[j] + a[i].z);
}
}
int max = 0;
for (i = 1; i <= tot; i++)
if (dp[i] > max) max = dp[i];
cout << "Case " << t++ << ": maximum height = " << max << endl;
}
return 0;
}