这题看了答案:http://cseweb.ucsd.edu/classes/sp00/cse202/dyn.pdf
题意大概是这样的,我有一些书,这些书的高度存在数组H里,厚度存在数组T里。书架有若干层,每层的宽度是固定的L,但是高度是可以自己调整的。在将这些书往书架中摆放的过程中,不能改变书的顺序。每一层的书的厚度总和不能超过L,每一层的书架的高度h必须大于等于这一层的书里最高的那个。问题是求摆放完这些书所需要的书架高度的最小值。
这是个动态规划的问题,但是怎么设计子状态的转移似乎有些困难。开始我想的是顺序的遍历所有的书,希望找到当前状态与之前的状态的关系,但是没想出><。于是去搜了搜答案,发现了一个挺棒的解法,主要思想是这样的:
定义目标是求cost[0],也就是序号为0的书它处于当前层的第一个位置时摆放所有书所需要的书架的总高度。cost[i]记录的是以序号为i的这本书作为当前层的第一本书,那么摆放i,i+1,....,n这些书所需要的书架的总高度。
这个问题可以被拆成下面的子问题:
cost[0] = min ( max(H[0],H[1],....H[k] )+cost[k+1] )
这里的k必须满足条件T[0]+T[1]+..+T[k] <= L ,也就是0~k这些书放在第一层,第一层的高度就是max(H[0],H[1],....H[k] )。 书k+1~书n占用的高度是cost[k+1]。 目标是让这两个高度和最小。
有了上面的状态转移方程之后代码就不难写了。这个问题需要从后向前遍历,依次求出cost[n],cost[n-1]....cost[1], cost[0].
代码如下,没有调试,所以只能凑合看个思想:
#include <vector> #include <iostream> using namespace std; int arrangeShelf(vector<int> height, vector<int> thick, int length) { int bookNum = height.size(); vector<int> cost(bookNum+1,0); vector<int> nextShelf(bookNum+1,bookNum);for(int i=bookNum-1;i>=0;i--) { cost[i] = thick[i]+cost[i+1]; } for(int i=bookNum-2;i>=0;i--) { int currentLen = thick[i];//当前层的总厚度 int currentMax = height[i];//当前层最高的书的高度 for(int j=i+1;j<bookNum;j++) { currentLen+=thick[j]; currentMax = max(currentMax, height[j]); if(currentLen>length) break; if(cost[j+1]+currentMax<=cost[i]) { cost[i] = cost[j+1]+currentMax; nextShelf[i] = j+1;//以i作为当前层的第一本书的话,那么下一层的第一本书的序号是nextShelf[i] } } }
//以下是打印当前书架的摆放方式 int i=0; int layer=0; while(i<bookNum) { int next = nextShelf[i]; cout<<"books in layer "<<layer<<" : "; while(i<next) { cout<<i<<" "; i++; } layer++; cout<<endl; } //返回最优情况下书架的高度 return cost[0]; }