题目概述:
用砖堆柱子,有kind种砖,每种砖都是长方体,长宽高分别为x,y,z,同一种砖的三个参数可以互换位置,最底层(地面)可放任意砖,但只有底面的长和宽(前两个参数)分别小于下层的,才可以放在下层的砖上面,并将这块砖的高(第三个参数)加到柱子的高度中
输入:
第一行kind,其后kind行每行x,y,z,多组数据之间没有空行,输入以0为一行结束
限制:
0<n<=30
输出:
每行一个字符串,若用%times%表示第times组数据(times从1开始),%ans%表示可以堆成的最高的柱子的高度,则字符串为
Case %times%: maximum height = %ans%
注意冒号右侧有空格,等号左右均有空格,%ans%后无空格
样例输入:
1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0
样例输出:
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
讨论:
这个题的一个小难点在于如何高效存储砖的数据,一个比较低效的实现是每种砖存一次,利用函数(或成员函数)在一砖砖内部三个参数互换后进行比较
从抽象模型上,可以视为有向无环的节点加权图,也可以看做简单的递归,但无论如何,着实有记忆化的思想
1.这里将每种砖的三个参数分别左移(不是<<运算符)一次,作为三种砖存储,由于check函数可以检查前两个参数互换的情况,因而少存了三次,也因此n只有30,而数组开到100
题解状态:
0 KB,0 ms,C++11 4.8.2,1383
#include<cmath>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<numeric>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<list>
#include<stack>
using namespace std;
struct node
{
int x;
int y;
int z;
};
node nodes[100];//用于存放每种砖的数据
int kind;//由于深搜需要知晓种数,为方便作为全局变量
int mem[100];//memory,存放从nodes中某种砖开始深搜所得最优解
inline bool ck(node &a, node &b)//check,检查是否能将一块砖放在另一块上方,可以检查长宽互换后的情况
{
return (a.x > b.x&&a.y > b.y) || (a.x > b.y&&a.y > b.x);
}
inline int maxx(int a, int b)//专用的max函数,敲了很多次,已经很熟练了
{
return a > b ? a : b;
}
int dfs(node &a, int b)//深搜,第二个参数是砖a在nodes里的序号,在迭代时一并传递,作为mem数组下标
{
int biggest = 0;//初始化深搜所得最优解为0
for (int p = 0; p < 3 * kind; p++) {//选择一块要放在上方的砖,因此深搜最深的砖是底面长宽最小的那个
if ((ck(a, nodes[p]))) {//判断能否放在上方
if (mem[p] != -1) {
biggest = maxx(biggest, mem[p]);//最优解已知,直接返回结果
} else {
biggest = maxx(biggest, dfs(nodes[p], p));//最优解未知,深搜
}
}
}
mem[b] = biggest + a.z;//退出深搜前将最优解记录
return mem[b];//返回上层深搜
}
int fun(int kind)
{
for (int p = 0; p < kind; p++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);//input
nodes[p].x = x, nodes[p].y = y, nodes[p].z = z;
nodes[p + kind].y = x, nodes[p + kind].z = y, nodes[p + kind].x = z;
nodes[p + 2 * kind].z = x, nodes[p + 2 * kind].x = y, nodes[p + 2 * kind].y = z;//参见讨论1
}
int biggest = 0;//初始化最大值
for (int p = 0; p < 3*kind; p++) {//从所有点开始深搜,由于深搜过一次后便在mem数组留下记录,因此多数深搜只是去读个数就返回
biggest = maxx(biggest, dfs(nodes[p], p));
}
return biggest;
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
int times = 0;//记数据序号
while (~scanf("%d", &kind) && kind) {//input
memset(mem, -1, sizeof(mem));
printf("Case %d: maximum height = %d\n", ++times, fun(kind));//output
}
}
EOF