程序员面试金典: 9.9 递归和动态规划 9.10求堆出箱子的最大高度
2017-01-10 15:39
357 查看
#include <iostream> #include <stdio.h> #include <vector> #include <map> using namespace std; /* 问题:给你一堆n个箱子,箱子宽Wi,高Hi,深Di。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子, 实现一个方法,搭出最高的一堆箱子,箱堆的高度为每个箱子高度的总和。 分析:这是汉诺塔问题吗?不是,汉诺塔是将一推从底下最大到顶上最小的盘子 从一个柱子转移到另一个柱子上。 搭出的高度要最大,显然只能把最底下箱子面积最大,依次从中选择次最大面积的箱子叠加在底下的箱子上面不就行了。 问题的关键在于:如果我找的第一个箱子宽度和深度最大的,但如果它的高度不高,第二个箱子虽然宽深都比第一个小, 但是高度比它高,那么其实选择第一个箱子和第二个箱子是要被第三个箱子来决定的。 这个问题需要动态规划来做。动态规划的特点是:无后效性和最优子结构。 1】最优子结构:最优化远离 2】无后向性:当前状态一旦确定,就不受状态之后的决策影响 原理:将问题分解为子问题,求解;适用含有重叠子问题 关键:需要确定状态转移方程,一般是某种递推的表示,而且是累加和的表示 设d[w][h][d]表示从起始箱子到当前摆放箱子(w,h,d)所拥有的最大高度, 设d[i]表示从初始第一个箱子到第i个箱子的最大高度,则所求结果为d , 特殊值:d[0]=0, 设i > j,有 d[i] = max{ d[i-j] + goods[j].h , } 实际可以用递归做,初始化指定一个底部的盒子,然后依次遍历放在其上面的盒子 输入: 5(n个箱子,接下来有n行,每一行3个数分别表示w,d,h) 10 8 5 8 6 7 7 7 4 5 5 6 1 1 1 输出: 14 关键: 1 计算所有箱子为底部箱子后对应的摆放箱子列表,然后从中选择出高度最高的箱子。初始底部箱子的选择是遍历整个箱子列表, 尝试把每个箱子放在底部来计算。得到需要将为底的箱子本身加入其上面的箱子列表,才组成从箱子底部到高处的结果 vector<Bin> createBins(vector<Bin>& bins ,Bin& bottom, map<Bin , vector<Bin> >& binToList ) { vector<Bin> vecBin; if(bins.empty()) { return vecBin; } //动态规划中记忆化搜索,如果已经求得了以bottom为底的箱子摆放箱子列表,那么直接返回 if( binToList.find(bottom) != binToList.end() ) { return binToList.find(bottom)->second; } //如果没有找到,那么就需要遍历所有箱子,判断每个箱子是否可以放在底部箱子之上,然后记录摆放后的高度,递归处理 int maxHeight = 0; vector<Bin> maxBins; int n = bins.size(); for(int i = 0 ; i < n ; i++) { //如果可以摆放,那么需要累加最大高度,应该先递归,再计算最大高度,而创建映射需要放在最后做 if( bins.at(i).canBeAbove(bottom) ) { vector<Bin> newBins = createBins(bins , bins.at(i) , binToList); int newHeight = getHeight(newBins); if(newHeight > maxHeight) { maxHeight = newHeight; maxBins = newBins; } } } //上面得到了最终的以某个箱子为底的摆放最大高度的箱子列表,下面需要将<为底的箱子,箱子列表>存入映射,方便记忆化搜索 //需要将为底的箱子本身加入其上面的箱子列表,才组成从箱子底部到高处的结果 maxBins.insert(maxBins.begin() , bottom); binToList.insert(pair<Bin , vector<Bin> >(bottom , maxBins)); //返回以bottom为底的箱子列表 return maxBins; } 2 //由于要作为map的键,因此,需要重写比较函数,map中必须有比较函数,优先以:w,d,h的顺序排列吧 // 用重载操作符operator<的方法做 bool operator < (const Student& stu) const , 函数末尾的conts会把this指针加上const然后与输入配对 bool operator < (const Bin& bin) const */ const int MAXSIZE = 10000; typedef struct Bin { Bin(){} Bin(int w, int d, int h):_w(w),_d(d),_h(h){} //判断当前箱子是否可以放在底部箱子bin,所以bin要大于当前 bool canBeAbove(Bin& bottom) { if( _w < bottom._w && _d < bottom._d && _h < bottom._h) { return true; } else { return false; } } //由于要作为map的键,因此,需要重写比较函数,map中必须有比较函数,优先以:w,d,h的顺序排列吧 // 用重载操作符operator<的方法做 bool operator < (const Student& stu) const ,函数末尾的conts会把this指针加上const然后与输入配对 bool operator < (const Bin& bin) const { if( _w != bin._w ) { return _w < bin._w; } else { if(_d != bin._d) { return _d < bin._d; } else { return _h < bin._h; } } } int _w; int _d; int _h; }Bin; int getHeight(vector<Bin>& bins) { if(bins.empty()) { return 0; } int size = bins.size(); int height = 0; for(int i = 0 ; i < size ; i++) { height += bins.at(i)._h; } return height; } /* 计算所有箱子为底部箱子后对应的摆放箱子列表,然后从中选择出高度最高的箱子 */ vector<Bin> createBins(vector<Bin>& bins ,Bin& bottom, map<Bin , vector<Bin> >& binToList ) { vector<Bin> vecBin; if(bins.empty()) { return vecBin; } //动态规划中记忆化搜索,如果已经求得了以bottom为底的箱子摆放箱子列表,那么直接返回 if( binToList.find(bottom) != binToList.end() ) { return binToList.find(bottom)->second; } //如果没有找到,那么就需要遍历所有箱子,判断每个箱子是否可以放在底部箱子之上,然后记录摆放后的高度,递归处理 int maxHeight = 0; vector<Bin> maxBins; int n = bins.size(); for(int i = 0 ; i < n ; i++) { //如果可以摆放,那么需要累加最大高度,应该先递归,再计算最大高度,而创建映射需要放在最后做 if( bins.at(i).canBeAbove(bottom) ) { vector<Bin> newBins = createBins(bins , bins.at(i) , binToList); int newHeight = getHeight(newBins); if(newHeight > maxHeight) { maxHeight = newHeight; maxBins = newBins; } } } //上面得到了最终的以某个箱子为底的摆放最大高度的箱子列表,下面需要将<为底的箱子,箱子列表>存入映射,方便记忆化搜索 //需要将为底的箱子本身加入箱子列表,否则整个列表最终会为空 maxBins.insert(maxBins.begin() , bottom); binToList.insert(pair<Bin , vector<Bin> >(bottom , maxBins)); //返回以bottom为底的箱子列表 return maxBins; } void process() { int n; vector<Bin> bins; map<Bin , vector<Bin> > binToList; vector<Bin> results; vector<Bin> maxResults; int w , d , h; while(cin >> n) { bins.clear(); binToList.clear(); for(int i = 0 ; i < n ; i++) { cin >> w >> d >> h; Bin bin(w , d, h); bins.push_back(bin); } //接下来计算最大高度,关键就是需要规定以某个箱子为底,这个应该需要遍历每一个箱子 int maxHeight = 0; for(int i = 0 ; i < n ; i++) { Bin bottom = bins.at(i); results = createBins(bins , bottom , binToList); int height = getHeight(results); //cout << height << endl; if(height > maxHeight) { maxHeight = height; maxResults = results; } } cout << maxHeight << endl; } } int main(int argc, char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- CareerCup 递归与动态规划 Q9.10 最大高度堆箱子
- 9.9递归和动态规划(十)——堆箱子
- 程序员面试金典: 9.9 递归和动态规划 9.5求字符串的全排列
- 程序员面试金典: 9.9 递归和动态规划 9.8求n分可以由25分,10分,5分,1分的硬币的表示方法
- 程序员面试金典: 9.9 递归和动态规划 9.6打印n对括号的全部有效组合
- 程序员面试金典: 9.9 递归和动态规划 9.11求布尔表达式的表达个数
- 程序员面试金典: 9.9 递归和动态规划 9.1上楼的方式
- 程序员面试金典: 9.9 递归和动态规划 9.1上楼的方式
- 程序员面试金典: 9.9 递归和动态规划 9.2机器人走路的方式
- 程序员面试金典: 9.9 递归和动态规划 9.4求某集合的所有子集
- 程序员面试金典: 9.9 递归和动态规划 9.9八皇后问题
- 程序员面试金典: 9.9 递归和动态规划 9.2机器人走路的方式_避免禁区
- 程序员面试金典: 9.9 递归和动态规划 9.7颜色填充
- 程序员面试金典: 9.9 递归和动态规划 9.3魔术索引
- 9.10 n个箱子,宽w、高h、深d,箱子不能翻转,下面的箱子的宽度、高度和深度必须大于上面的,实现一个方法,搭出最高的一堆箱子。
- 9.9递归和动态规划(三)——魔术索引
- 9.9递归和动态规划(六)——打印n对括号的全部有效组合(即左右括号正确配对)
- 9.9递归和动态规划(九)——N皇后
- 9.9递归和动态规划(十一)——算出有几种括号的放法可使该表达式得出result值
- 经典算法题:数字三角形寻找最大路径——动态规划和递归调用两种解法