HDU1069(DP)
这道题较为简单,有了前面DP的基础后,拿到这道题,怎么想呢?我现在理解DP问题就是找到一个方法,能把总问题由上到下分解,有点类似学校安排迎新晚会,任务出来了,然后老师交给学生会主席,学生会主席把任务分解成一个个小任务,安排给各个部门,各个部门的部长再细分成更小的任务给部员,到部员的时候任务就变得可实现了,就可以完成,然后把结果反馈给部长,部长再反馈给主席,而DP的重点就是找到一个相同的任务,使得主席安排给部长的和部长安排给部员的任务是一样的。
面对这道题,先提取出状态,我所提取的是一个箱子的一种摆法(class pos),比如3 4 5 的箱子,就有三种摆法,5 5 10的箱子有两种摆法,然后每种摆法上面可以摆的箱子用UP数组存储,摆的动作用add函数,注意到是UP里包含了所有在this箱子之上的所有箱子,但实际用哪个箱子放在this上面不需要考虑,这就体现出了DP的特点,我只需要安排出任务,而且确定任务在循环中一定能解决即可,不需要关心任务的中间步骤,这样,先循环确定每一个摆法上面可能有的所有情况,然后再计算哪一种最高(heigh())即可。
#include<iostream>
#include<string>
using namespace std;
class pos {//每一种摆法含有数据还有操作,所以抽象出一个类
public:
int min;
int max;
int h;
int heigh();
int MaxHeight;
pos *up[100];//用于确定this箱子上可以有哪些箱子
int top ;
void add(pos &a);
void creat(int a, int b, int c);
};
int pos::heigh() {
int a = 0;
for (int i = 1;i <= top;i++) {//利用MaxHeight存储已经计算过的,减少heigh()的使用,减少时间
if (up[i]->MaxHeight == 0)
a = (a > up[i]->heigh() ? a : up[i]->heigh());
else
a = (a > up[i]->MaxHeight ? a : up[i]->MaxHeight);
}
MaxHeight = a + this->h;
return a + this->h;
}
void pos::add(pos &a) {
if(a.min<this->min&&a.max<this->max)
up[++top] = &a;
}
void pos::creat(int a, int b, int c) {
min = a;max = b;h = c;
top = 0;
MaxHeight = 0;
}
int max(int a, int b) {
return (a >= b ? a : b);
}
int main() {
int all;
int cal = 0;
while (cin >> all) {
if (all == 0)
break;
int p = 0;
pos head[100];
int PutWay = 0;
for (int i = 1;i <= all;i++) {//这个for循环是为了让长宽高小到大排列,方便后面比较
int x, y, z;
cin >> x >> y >> z;
int a, b, c;
c = max(max(x, y), z);
if (z == c)
b = max(x, y);
else if (c == x)
b = max(y, z);
else
b = max(x, z);
a = x + y + z - c - b;
if (a == c) {//不同规格的箱子有不同的摆法
head[++PutWay].creat(a, b, c);
continue;
}
else if (a == b) {
head[++PutWay].creat(a, b, c);
head[++PutWay].creat(a, c, b);
continue;
}
else if (b == c) {
head[++PutWay].creat(a, b, c);
head[++PutWay].creat(b, c, a);
continue;
}
else {
head[++PutWay].creat(a, b, c);
head[++PutWay].creat(a, c, b);
head[++PutWay].creat(b, c, a);
}
}
for (int i = 1;i <= PutWay;i++)
for (int j = 1;j <= PutWay;j++)
head[i].add(head[j]);//双重循环,在i上对于每一种j都add上去,符合就进up,不符合则不进
int mmax = -1;
for (int i = 1;i <= PutWay;i++)
mmax = max(mmax, head[i].heigh());
cout << "Case " <<(++cal)<< ": maximum height = " << mmax<< endl;
}
}
一开始提交几次都是超时,利用MaxHeight优化后才通过,这里想到了之前看到的一篇文章,讲DP的优点,其中一个就是有一些中间数据是重复利用的,像这道题的每个pos的MaxHeight就反复利用,如果用heigh()的话就是大量的递归。
其实感觉DP和递归还有没太搞懂的递推蛮像的,但是中间数据的复用使DP效率能提高一些。