POJ 1787 Charlie's Change (完全背包/多重背包,输出方案的物品个数)

网上说是多重背包,因为要输出方案,还要记录下路径,百度一下题解就可以。

自己做的时候,还没了解过多重背包,该题直接往完全背包思考了。
咖啡的钱看作总的背包容量,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;
}
原文地址:https://www.cnblogs.com/chenxiwenruo/p/3470161.html