Poj 3260 The Fewest Coins (DP_背包)

题目链接:http://poj.org/problem?id=3260


题目大意:农民John去购物,市面流行的硬币有n种,每种面值mon[i],John有num[i]个,现在他要到煤老板的店里去买m元的东西,大家都知道煤老板不差钱,每种硬币都有无数个,煤老板找钱的话都可以找最少数量的硬币给John,现在John想要自己出的硬币数和老板找的硬币数最小,如果找不到符合情况的解,输出-1.


解题思路:Usaco的题目质量我觉得还不错,做了几道算法应用题,难度中等,挺适合这个阶段的自己。本题需要用多重背包和完全背包解,算比较综合的题目。因为每次找钱的数量是一定的,我们可以提前用完全背包算出j元钱需要的最少硬币数minn[j]。将找钱的最少硬币预处理完之后,就可以开始进行多重背包求解,因为数据量比较大必须用二进制先进行处理,处理成数量最多为1500左右的物品,然后用01背包求解。当John给煤老板超过m元钱的时候有三种情况:刚好是m元,那就可以用这个更新答案,如果大于m元并且能找的断,那也用这次计算的硬币数更新答案,如果找不断,那么需要一直给煤老板钱,直到老板找得了钱或者你没钱。其实给的钱会有个临界值,我设为m + 10000了。

    状态转移方程:if (j >= m && dp[j-cost[i]]+minn[j-m]+val[i] < dp[j]) dp[j] = dp[j-cost[i]]+minn[j-m]+val[i];
                               else dp[j] = min(dp[j],dp[j-cost[i]]+val[i]);

   复杂度O((V+10000)*sum(log(num[i]))


测试数据:

3 60
32 39 50
1 2 1

3 70
1 2 3
1 2 3

3 70
40 50 60
0 0 0

3 70 
50 60 90
1 1 1

3 7
1 2 3
2 1 1

3 4
3 101 100
1 1 0


代码:

#include <stdio.h>
#include <string.h>
#define MAX 20000
#define INF 100000000
#define min(a,b) (a)<(b)?(a):(b)


int tot,cost[MAX],val[MAX];
int minn[MAX],dp[MAX],maxval;
int n,m,ans,mon[MAX],num[MAX];


void Initial() {

	int i,j,k,tpk;


	for (i = 0; i <= m + maxval; ++i)
		dp[i] = minn[i] = INF;
	minn[0] = dp[0] = 0;

	//煤老板找钱的最少数量,硬币无限
	for (i = 1; i <= n; ++i)
		for (j = mon[i]; j <= m + maxval; ++j)
			minn[j] = min(minn[j],minn[j-mon[i]]+1); 

	//将各种物品,二进制处理若干件物品
	for (tot = 0,i = 1; i <= n; ++i) {

		for (k = 0; (1<<k) <= num[i]; ++k) {

			num[i] -= (1<<k);
			cost[++tot] = mon[i] * (1<<k);
			val[tot] = (1<<k);
		}
		if (num[i]) 
			cost[++tot] = mon[i] * num[i],val[tot] = num[i];
	}
}


int main()
{
	int i,j,k;


	while (scanf("%d%d",&n,&m) != EOF) {

		maxval = 10000;
		for (i = 1; i <= n; ++i) 
			scanf("%d",&mon[i]);
		for (i = 1; i <= n; ++i)
			scanf("%d",&num[i]);
	

		Initial(),ans = INF;
		for (i = 1; i <= tot; ++i)
			for (j = m + maxval; j >= cost[i]; --j) {
				
				if (j >= m && dp[j-cost[i]]+minn[j-m]+val[i] < dp[j]) {
					
					dp[j] = dp[j-cost[i]]+minn[j-m]+val[i];
					ans = min(dp[j],ans);
				}
				else dp[j] = min(dp[j],dp[j-cost[i]]+val[i]);
			}


		if (ans >= INF) printf("-1\n");
		else printf("%d\n",ans);
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(算法,测试)