【完全背包问题】
是对0-1背包问题的扩展,每种物品不只可以取一件,而是可以选择多件,每种物品的数量均为无限个。
将情况分为是否放入第i件物品两种:
(1)不放,dp[i][j]=dp[i-1][j]
(2)放,dp[i][j]=dp[i][j-w[i]]+v[i](因为第i件物品仍然可取)
优化为一维数组:dp[j]=max(dp[j],dp[j-w[i]]+v[i])
注:每次更新时,需要正序地遍历所有j的值,才能保证在确定dp[j]的值时,dp[j-w[i]]的值已被修改(因为是第i层不再是第i-1层)
Piggy-Bank
题意:
ACM在做任何事情之前,必须编制预算以获得必要的财政经费支持,而财政经费的来源则来自“不可逆转的束缚货币”(Irreversibly Bound Money,IBM)。这一做法的思想很简单。某个ACM成员只要有一点零钱,他就要把所有的硬币都扔进一个储蓄罐。如您所知,这个过程是不可逆的,如果不打破储蓄罐的话,硬币就不能被取出。在足够长的时间之后,储蓄罐里就会有足够的钱来支持所有需要进行的工作。
但是储蓄罐有一个大问题,就是不能确定里面有多少钱。这就有可能在我们把储蓄罐打碎之后,结果却发现钱不够。我们希望能够避免这种情况,唯一可能的方法就是称一下储蓄罐的重量,然后试着猜测里面有多少硬币。本题设定,我们能够精确地确定储蓄罐的重量,并且我们知道每一种硬币的重量。本题需要确定在储蓄罐里可以保证有的最低总金额。请您找出最坏的情况,确定储蓄罐内的最小的现金量。我们需要您的帮助,不要过早地打碎储蓄罐。
输入
输入给出T个测试用例。在输入的第一行给出测试用例的数目T。每个测试用例的第一行给出两个整数E和F,表示空的储蓄罐和装满硬币的储蓄罐的重量,这两个重量均以克为单位。储蓄罐的重量不会超过10公斤,也就是说,1 <= E <= F <= 10000。在测试用例的第二行给出一个整数N(1 <= N <= 500),给出在给定的货币体系中硬币的种类数量。接下来的N行,每行给出两个整数P和W(1 <= P <= 50000, 1 <= W <= 10000)表示一种硬币,P是该种硬币的面值,W是该种硬币的重量,单位是克。
输出
对于每个测试用例,输出一行。该行输出“The minimum amount of money in the piggy-bank is X.”,其中X是给定硬币总重量,储蓄罐内可以达到的最小金额。如果对于给出的硬币重量,无法计算出储蓄罐内的最小金额,则输出一行“This is impossible.”。
示例:
输入
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
输出
The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.
#include<bits/stdc++.h>
using namespace std;
const int MAXN=10000;
const int INF=INT_MAX/10;
//完全背包问题,求最小值
//完全背包允许放多件物品
int v[MAXN];//价值
int w[MAXN];//重量
int dp[MAXN];
int main(){
int c,n;
int number;
cin>>number;
while(number--){
int e,f;
cin>>e>>f;
int c=f-e;//背包容量
cin>>n;
for(int i=0;i<n;i++){
cin>>v[i]>>w[i];
}
dp[0]=0;
for(int i=1;i<=c;i++){
dp[i]=INF;//初始化
//循环c次,转换为一维,因为后面要用到
//因为在整个二维的表格中,前面的都一样
//只需要最后的一个元素,所以其他层的元素不用考虑
}
for(int i=0;i<n;i++){
for(int j=w[i];j<=c;j++){
//之所以是顺序,是因为需要dp[j-w[i]]是第i层更新后的不再是第i-1层更新的
dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
}
}
if(dp[c]==INF){
cout<<"This is impossible."<<endl;
}
else{
cout<<"The minimum amount of money in the piggy-bank is "<<dp[c]<<"."<<endl;
}
}
return 0;
}