POJ 1742 Coins (多重背包的两种解法)

题意:

先输入输入每种硬币的价值,再输入每种硬币的个数

求在m以内能组成几种价值

题目意思与HDU 2844相同,但是HDU的那题用二进制优化来做,在POJ上过不了,所以又学了一种方法来解这题

思路一:二进制优化

二进制优化实际上就是将题目转化为01背包来做

例如,一个13件的物品,按照二进制转化的思路,转化成1 ,2 ,4 ,6

前面是2的幂次,最后一件物品是剩下的件数

这样做的原因是,这样拆了以后,这些件数可以组成1到13的所有数字,所以用01背包来做,可以考虑到所有情况,但是物品n的复杂度减少到log(n)

#include 
#include  
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
bool dp[100010];
int v[110];
int save[10000];
int main()
{
//    freopen("D://input.txt", "r", stdin);
//    freopen("D://output.txt", "w", stdout);
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF&&n&&m)
    {
        int i, j, k, len = 0;
        for (i = 1; i <= m; i++)
            dp[i] = false;
        for (i = 0; i < n; i++)
            scanf("%d", &v[i]);
        int num;
        for (i = 0; i < n; i++)//输入物品个数时
        {
            scanf("%d", &num);
            int q = 1;
            while (q < num)
            {
                save[len++]=q*v[i];
                num -= q;
                q *= 2;
            }
            save[len++] = num*v[i];
        }
        dp[0] = true;
        for (i = 0; i < len; i++)
        {
            for (j = m; j >= save[i]; j--)
            {
                if (!dp[j])
                    dp[j] = dp[j-save[i]];
            }
        }
        int cot = 0;
        for (i = 1; i <= m; i++)
        {
            if (dp[i])
                cot++;
        }
        printf("%d\n", cot);
    }
//    printf(".6lf\n",(double)clock()/CLOCKS_PER_SEC);
    return 0;
}
思路二:

在dp的时候记录每个硬币的使用次数,超过上限了就不能再使用

其实这样的做法是以完全背包的思路来做。只不过加了个数的限制,超过限制以后就停止使用这种硬币

#include
#include
#include
using namespace std;
int n, m;
int dp[100010], sum[100010];
int val[110], c[110];
int main()
{
//	freopen("input.txt", "r", stdin);
	while (scanf("%d%d", &n, &m) != EOF && n && m)
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &val[i]);
		for (int i = 1; i <= n; i++)
			scanf("%d", &c[i]);
		memset(dp, 0, sizeof(dp));
		dp[0] = 1;
		int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			memset(sum, 0, sizeof(sum));
			for (int l = val[i]; l <= m; l++)
			{
				if (!dp[l] && dp[l - val[i]] && sum[l - val[i]] < c[i])
				{
					dp[l] = 1;
					sum[l] = sum[l - val[i]] + 1;
					ans++;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}



你可能感兴趣的:(DP)