题目大意:
FJ最近买了一座书架给奶牛图书馆,但是书架很快就被书填满了,现在只有顶上的一点空间可以放新书了,FJ现在有N头奶牛(1 ≤ N ≤ 20),每头牛的高度为[1, 1000000],而书架的高度为B(1 ≤ B ≤ S,S是所有牛高度的总和),为了达到书架的顶端牛可以叠罗汉,为了翻看顶端的书叠罗汉的高度不得小于B,但是叠的越高越危险,现在的任务就是求叠罗汉最少可以超过B多少。
现只有一个测例,测例中给出N和B,接下来会给出每头奶牛的高度,要求输出叠罗汉最少可以超过B多少。
注释代码:
/*
* Problem ID : POJ 3628 Bookshelf 2
* Author : Lirx.t.Una
* Language : C
* Run Time : 0 ms
* Run Memory : 320 KB
*/
#include <stdio.h>
//maximum exceeded height
//超出书架部分的最大长度
//20 × 1,000,000 - 1
#define MAXXDH 19999999
//maximum number of cows
//奶牛的最大数量
#define MAXCOWN 21
#define MAX(x,y) ( (x) > (y) ? (x) : (y) )
//思路是先将所有奶牛高度相加再减去书架高度得到xd,表示最多可以超出多少高度
//再在这个xd中最多可以承受奶牛的高度dp
//xd - dp就是最小的超出书架的高度了
//因此可以讲xd看做背包,最终可以怎样往背包中放奶牛可以使得背包的价值最大(高度)
//而且的就是总价值(高度)减去这个最大价值(高度)
int h[MAXCOWN];//height[i]表示第i头奶牛的高度,从下标1开始
//dp[i][j]表示i号奶牛放入高度为j的背包中所得的最大高度
//由01背包问题的结论得显然有dp[i][j] = MAX( dp[i - 1][j], dp[i - 1][ j - h[i] ] )
//前者表示i不放入背包,后者表示i放入背包
//因此可以看到数组dp[i]的值只与数组dp[i - 1]数组有关
//因此可以只用一个数组来表示滚动数组,将i这一维度给隐藏以减少空间
int dp[MAXXDH];
int
main() {
int n, b;//奶牛数量和书架高度
int toth;//total height of cows,奶牛的总高度
int xd;//exceeded height,所有奶牛高度超出书架的高度
int i, j;//计数变量
int tmp;//临时变量
scanf("%d%d", &n, &b);
for ( toth = 0, i = 1; i <= n; i++ ) {
scanf("%d", h + i);
toth += h[i];
}
for ( xd = toth - b, i = 1; i <= n; i++ )
//注意动态规划的方向是从后往前的,即从xd向h[i]方向动态规划的
//注意dp[i][x]是用dp[i - 1][x]更新的,更新完了以后就变成了dp[i][y]了
//具体讲,如果dp[2][3]已经用dp[1][2]更新了,等到dp[2][5]使用dp[1][3]更新时
//使用的其实是dp[2][3],因为这里使用的是一维滚动数组,把i维隐藏了,一旦先更新了
//前面的值,则后面的值更新时用的就不是上一维的了而是更新后的这一维的数据了
for ( j = xd; j >= h[i]; j-- ) {
tmp = dp[ j - h[i] ] + h[i];//相当于dp[i - 1][ j - h[i] ]
dp[j] = MAX( dp[j], tmp );//相当于dp[i][j] = MAX( dp[i - 1][j], dp[i - 1][ j - h[i] ] )
}
printf("%d\n", xd - dp[xd]);
return 0;
}
无注释代码:
#include <stdio.h>
#define MAXXDH 19999999
#define MAXCOWN 21
#define MAX(x,y) ( (x) > (y) ? (x) : (y) )
int h[MAXCOWN];
int dp[MAXXDH];
int
main() {
int n, b;
int toth;
int xd;
int i, j;
int tmp;
scanf("%d%d", &n, &b);
for ( toth = 0, i = 1; i <= n; i++ ) {
scanf("%d", h + i);
toth += h[i];
}
for ( xd = toth - b, i = 1; i <= n; i++ )
for ( j = xd; j >= h[i]; j-- ) {
tmp = dp[ j - h[i] ] + h[i];
dp[j] = MAX( dp[j], tmp );
}
printf("%d\n", xd - dp[xd]);
return 0;
}
单词解释:
bookshelf:n, 书架
fill up:vi, 填满
stack:n, 堆,垛堞