http://acm.hdu.edu.cn/showproblem.php?pid=1114
题意大致是:一个可以放V这么大的钱罐,往里面放n种钱,如果放不满则输出impossible,否则输出价值最小情况。
这个算法使用一维数组:
for (i=1;i<=n;++i)
{
for (j=c[i];j<=v;++j) s[j]=max(s[j],s[j-c[i]]+w[i]);
}
01背包:因为要保证第 i次循环中的状态 s[i][j]是由状态s[i-1][j-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次。
完全背包:而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i种物品”这种策略时,却正需要一个可能已选入第 i种物品的子结果s[i][j-c[i]],所以就可以并且必须采用 j=0..V的顺序循环。这就是这个简单的程序为何成立的道理。
{
for (j=c[i];j<=v;++j) s[j]=max(s[j],s[j-c[i]]+w[i]);
}
01背包:因为要保证第 i次循环中的状态 s[i][j]是由状态s[i-1][j-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次。
完全背包:而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i种物品”这种策略时,却正需要一个可能已选入第 i种物品的子结果s[i][j-c[i]],所以就可以并且必须采用 j=0..V的顺序循环。这就是这个简单的程序为何成立的道理。
#include <iostream>
using namespace std;
#define N 505
#define W 10005
#define M 50005*505 //起初这个最大值弄错了,WA了好几次。
int value[N],weight[N],sum[W];
int min(int a,int b){
return a>b?b:a;
}
int main(){
int t,volume,e,f,n,i,j;
scanf("%d",&t);
while (t--){
scanf("%d%d",&e,&f);
volume=f-e;
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d%d",&value[i],&weight[i]);
for (i=1;i<=volume;i++)
sum[i]=M;
sum[0]=0;
for (i=1;i<=n;i++)
for (j=weight[i];j<=volume;j++){
sum[j]=min(sum[j],sum[j-weight[i]]+value[i]);
}
if (sum[volume]<M)
printf("The minimum amount of money in the piggy-bank is %d.\n",sum[volume]);
else printf("This is impossible.\n");
}
return 0;
}