首页 > 代码库 > POJ 1742 Coins 【多重背包DP】

POJ 1742 Coins 【多重背包DP】

题意:有n种面额的硬币。面额、个数分别为A_i、C_i,求最多能搭配出几种不超过m的金额?

思路:dp[j]就是总数为j的价值是否已经有了这种方法,如果现在没有,那么我们就一个个硬币去尝试直到有,这种价值方法有了的话,那么就是总方法数加1。多重背包可行性问题

传统多重背包三重循环会超时,因为只考虑是否可行,没有考虑剩余面额数量的因素。

o(n*v)方法

#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;

int dp[100005]; //表示当前i价格是否出现过
int sum[100005];//当价格达到i时,最多使用这一种硬币的次数
int v[105],c[105];

int main()
{
    int i,j,n,m;
    while(~scanf("%d%d",&n,&m),n+m)
    {
        for(i = 1;i<=n;i++)
            scanf("%d",&v[i]);
        for(i = 1;i<=n;i++)
            scanf("%d",&c[i]);
        memset(dp,0,sizeof(dp));
        dp[0] = 1;
        int ans = 0;
        for(i=1;i<=n;i++)
        {
            memset(sum,0,sizeof(sum));//关键是用sum来限定了次数
            for(j = v[i];j<=m;j++)//循环检查看是否能够出现前边没有出现的价格
            {
                if(!dp[j] && dp[j-v[i]] && sum[j-v[i]]<c[i])
				{ //如果j价格没有出现过,且j-v[i]出现过,并且使用i硬币的次数没有超出给定的数量
                    dp[j] = 1;
                    sum[j] = sum[j-v[i]]+1;//使用次数+1
                    ans++;
                }
            }
        }
        printf("%d\n",ans);
    }
    
    return 0;
}

POJ 1742 Coins 【多重背包DP】