POJ 1384 Piggy-Bank(完全背包)
http://poj.org/problem?id=1384
题意:
现在有n种硬币,每种硬币有特定的重量cost[i] 克和它对应的价值val[i]. 每种硬币可以无限使用. 已知现在一个储蓄罐中所有硬币的总重量正好为m克, 问你这个储蓄罐中最少有多少价值的硬币? 如果不可能存在m克的情况, 那么就输出” This is impossible.”.
分析:
由于每种硬币可以无限使用, 所以是明显的完全背包问题.
本题的限制条件: 硬币总重量正好等于m.
本题的目标条件: 硬币总价值尽量小.
令dp[i][j]==x 表示只用前i种货币, 且当总重量达到j克时的最小价值和为x.
初始化: 所有dp都为INF(无穷大), 且dp[0]==0. (因为本题的目标是价值最小,所以初始化为无穷大. 如果要让目标最大, 那么应该初始化为-1. )
状态转移: dp[i][j] = min( dp[i-1][j] , dp[i][j-cost[i]]+val[i])
上面方程前者表示第i种硬币一个都不选, 后者表示至少选1个第i种硬币.
最终所求为dp[n][m]. (如果dp[n][m]==INF, 说明m克是一个不可达的状态)
本题程序用的滚动数组, 所以dp只有[j]这一维.
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10000+5; #define INF 1e9 int n;//货币种数 int m;//最大重量 int dp[maxn]; int cost[maxn];//每种货币重量 int val[maxn]; //每种货币价值 int main() { int T; scanf("%d",&T); while(T--) { //读入数据 int m1,m2; scanf("%d%d%d",&m1,&m2,&n); m=m2-m1; for(int i=1;i<=n;i++) scanf("%d%d",&val[i],&cost[i]); //初始化 for(int i=0;i<=m;i++) dp[i]=INF; dp[0]=0; //递推过程 for(int i=1;i<=n;i++) { for(int j=cost[i];j<=m;j++) dp[j] = min(dp[j], dp[j-cost[i]]+val[i]); } //输出结果 if(dp[m]==INF) printf("This is impossible.\n"); else printf("The minimum amount of money in the piggy-bank is %d.\n",dp[m]); } return 0; }