网上说是多重背包,因为要输出方案,还要记录下路径,百度一下题解就可以。
自己做的时候,还没了解过多重背包,该题直接往完全背包思考了。
咖啡的钱看作总的背包容量,1、5、10、25分别代表四种物品的重量,可以取多次,但是有限制数量。
设dp[j]为咖啡的价格为j时,所能花费的最多钱币数
此外建立一个二维数组num[j][i],表示咖啡的价格为j时,花费的第i种货币的个数
状态转移方程:
dp[j]=max(dp[j],dp[j-v[i]]+1)
初始条件:dp[j]=-1,dp[0]=0;
num[j][i]=0;
若dp[j-v[i]]+1>dp[j],则
num[j][i]=num[j-v[i]]+1; 当然有个限制条件:num[j-v[i]]+1<=c[i]
num[j][k]=num[j-v[k]]; (k!=i)
#include <iostream> #include <stdio.h> #include <cstring> #include <algorithm> using namespace std; const int maxn=10001; int dp[maxn]; //dp[j]为咖啡的价格为j时,所能花费的最多钱币数 int V; int c[4]; //四种货币的限制个数 int v[5]={1,5,10,25}; int num[maxn][5]={0}; //num[j][i],表示咖啡的价格为j时,花费的第i种货币的个数 int main() { while(scanf("%d%d%d%d%d",&V,&c[0],&c[1],&c[2],&c[3])!=EOF){ if(c[0]==0&&c[1]==0&&c[2]==0&&c[3]==0&&V==0){ break; } dp[1]=1; memset(dp,-1,sizeof(dp)); memset(num,0,sizeof(num)); dp[0]=0; for(int i=0;i<4;i++){ for(int j=v[i];j<=V;j++){ //这里要注意dp[j-v[i]]得可到达 if(dp[j-v[i]]!=-1 && dp[j-v[i]]+1>dp[j]&&num[j-v[i]][i]<c[i]){ dp[j]=dp[j-v[i]]+1; for(int k=0;k<4;k++){ if(k==i){ num[j][k]=num[j-v[i]][k]+1; } else{ num[j][k]=num[j-v[i]][k]; } } } } } if(dp[V]==-1) printf("Charlie cannot buy coffee. "); else printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters. ",num[V][0],num[V][1],num[V][2],num[V][3]); } return 0; }