Bookshelf 2
Description
Farmer John recently bought another bookshelf for the cow library, but the shelf is getting filled up quite quickly, and now the only available space is at the top.
FJ has N cows (1 ≤ N ≤ 20) each with some height of Hi (1 ≤ Hi ≤ 1,000,000 - these are very tall cows). The bookshelf has a height of B (1 ≤ B ≤ S, where S is the sum of the heights of all cows).
To reach the top of the bookshelf, one or more of the cows can stand on top of each other in a stack, so that their total height is the sum of each of their individual heights. This total height must be no less than the height of the bookshelf in order for the cows to reach the top.
Since a taller stack of cows than necessary can be dangerous, your job is to find the set of cows that produces a stack of the smallest height possible such that the stack can reach the bookshelf. Your program should print the minimal ‘excess’ height between the optimal stack of cows and the bookshelf.
Input
- Line 1: Two space-separated integers: N and B
- Lines 2…N+1: Line i+1 contains a single integer: Hi
Output
- Line 1: A single integer representing the (non-negative) difference between the total height of the optimal set of cows and the height of the shelf.
Sample Input
5 16
3
1
3
5
6
Sample Output
1
题意: 给定n只牛,以及这n只牛的高度,书架的高度。求从这n只牛选出一部分牛(最少的牛的数量)堆叠起来的高度与书架的高度最小的差值。
题解:
- 背包方法:用一个数组来记录牛的数量,该数组的下标表示选出的牛的总重量。如用
d
p
[
j
]
dp[j]
dp[j] 代表在总重量为j的情况下最少需要的牛的数量。
- 如果我们在之前的状态中存在一个重量是 j − w [ i ] j - w[i] j−w[i] 那么我们刚好在当前步可以加上第 i 只牛,它的重量为 w[i],这时候总重量就变为了 j 此时 dp[j] 里面储存的牛的数量加一(因为这只牛加进来了嘛)。
- 另一种情况,我们不选第 i 只牛总重量就达到的 j 这时候它的数组里面储存的牛的数量就是之前达到的牛的数量。
- 综合上面两种情况我们可以推导出状态转移方程 d p [ j ] = m i n ( d p [ j ] , d p [ j − w [ i ] ] + 1 dp[j] = min(dp[j], dp[j - w[i]]+1 dp[j]=min(dp[j],dp[j−w[i]]+1
- 深度优先搜索方法:详细逻辑见代码。
c++ AC 代码(背包方法)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define sz 1000000
#define INF 0x3f3f3f3f
using namespace std;
int dp[sz];
int w[20];
bool cmp(const int a, const int b)
{
return a > b;
}
int main()
{
int n, m, sum = 0;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> w[i];
sum += w[i];
}
if (sum == m)
{
puts("0");
return 0;
}
memset(dp, INF, sizeof(dp));
sort(w, w + n, cmp);
dp[0] = 0;
for (int i = 0; i < n; i++)
for (int j = m + w[0]; j >= w[i]; j--)
dp[j] = min(dp[j], dp[j - w[i]] + 1);
int ans = -1;
for (int i = m; i <= w[0] + m; i++)
if (dp[i] != INF)
{
ans = abs(m - i);
break;
}
cout << ans << endl;
// system("pause");
return 0;
}
c++ AC 代码(dfs版)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define sz 1000000
#define INF 0x3f3f3f3f
using namespace std;
int w[20];
int n, m, sum = 0;
int ans = 0;
void dfs(int k, int total_sum)
{
if (total_sum == m) // 如果某个数恰好等于m,返回,将ans设置为0(它两的高度差为0)
{
ans = 0;
return;
}
if (total_sum > m)
{
if (total_sum - m < ans) // 如果它两的高度差比之前搜索过的高度差小,更新ans
ans = total_sum - m;
return;
}
for (int i = k; i < n; i++)
dfs(i + 1, total_sum + w[i]);
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
cin >> w[i];
sum += w[i];
}
if (sum == m) // 如果所有的牛的重量加起来刚好等于总重量m,直接输出0
{
puts("0");
return 0;
}
ans = sum;
dfs(0, 0);
cout << ans << endl;
// system("pause");
return 0;
}