混合背包(多重背包+完全背包)—— POJ 3260

对应POJ题目:点击打开链接

The Fewest Coins

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 5450   Accepted: 1653

Description

Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus the number of coins he receives
in change is minimized. Help him to determine what this minimum number is.

FJ wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1V2, ..., VN (1 ≤ Vi ≤
120). Farmer John is carrying C1 coins of value V1C2 coins of valueV2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000).
The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner (although Farmer John must be sure to pay in a way that makes it possible to make the correct change).

Input

Line 1: Two space-separated integers: N and T.

Line 2: N space-separated integers, respectively V1V2, ..., VN coins (V1, ...VN)

Line 3: N space-separated integers, respectively C1C2, ..., CN

Output

Line 1: A line containing a single integer, the minimum number of coins involved in a payment and change-making. If it is impossible for Farmer John to pay and receive exact change, output -1.

Sample Input

3 70
5 25 50
5 2 1

Sample Output

3

Hint

Farmer John pays 75 cents using a 50 cents and a 25 cents coin, and receives a 5 cents coin in change, for a total of 3 coins used in the transaction.

题意:给出n种面额的硬币以及每种面额的数量,买要T元的商品,给多了老板会找钱,老板也有n种面额的硬币,但没有数量限制,问在买T元的商品这个交易的过程中硬币交易的数量最少是多少(即是用来买商品的硬币数量跟老板找零的硬币数量的和最小是多少)

思路:买商品的钱有限,是多重背包问题,dp_buy[i]表示支付为i时需要的最少硬币数量;老板找零的硬币无限,是完全背包问题,dp_sell[i]表示找钱为i时需要的最少硬币数量;则min{dp_buy[i] + dp_sell[i-T]}即为所求。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define INF (1<<30)
#define MAXN 110
#define MAXT 24410
int dp_buy[MAXT]; //dp_buy[i]表示支付为i时需要的最少硬币数量
int dp_sell[MAXT]; //dp_sell[i]表示找钱为i时需要的最少硬币数量
int v[MAXN];
int c[MAXN];
int v_b[MAXN*15]; //二进制拆分后的硬币面值
int c_b[MAXN*15]; //二进制拆分后的硬币数量
int N, T;

int main()
{
	//freopen("in.txt", "r", stdin);
	int i, j, k, u, max_e, min_s, V;
	while(~scanf("%d%d", &N, &T))
	{
		max_e = 0; //最大的硬币面值
		u = 0;

		for(i = 1; i <= N; i++){
			scanf("%d", v + i);
			if(v[i] > max_e) max_e = v[i];
		}

		for(i = 1; i <= N; i++){
			scanf("%d", c + i);
			//二进制拆分
			j = 1;
			k = c[i];
			while(j <= k)
			{
				++u;
				v_b[u] = j * v[i];
				c_b[u] = j;
				k -= j;
				j <<= 1;
			}
			if(k > 0){
				++u;
				v_b[u] = k * v[i];
				c_b[u] = k;
			}
		}

		V = T + max_e * max_e; //付钱的最大金额

		for(i= 0; i <= V; i++) dp_sell[i] = dp_buy[i] = INF;
		dp_sell[0] = dp_buy[0] = 0;

		for(i = 1; i <= N; i++) //完全背包算出找零的最小数量
			for(j = v[i]; j <= V - T; j++)
				dp_sell[j] = MIN(dp_sell[j - v[i]] + 1, dp_sell[j]);

		for(i = 1; i <= u; i++) //多重背包(转化为01背包)算出付钱的最小数量
			for(j = V; j >= v_b[i]; j--)
				dp_buy[j] = MIN(dp_buy[j - v_b[i]] + c_b[i], dp_buy[j]);

		min_s = INF;

		for(i = T; i <= V; i++){
			if(dp_buy[i] == INF || dp_sell[i-T] == INF) continue;
			if(dp_buy[i] + dp_sell[i-T] < min_s)
				min_s = dp_buy[i] + dp_sell[i-T];
		}

		if(min_s != INF) printf("%d\n", min_s);
		else printf("-1\n");
	}
	return 0;
}
时间: 2024-11-09 00:50:30

混合背包(多重背包+完全背包)—— POJ 3260的相关文章

POJ 3260 The Fewest Coins(多重背包+全然背包)

http://poj.org/problem?id=3260 题意: John要去买价值为m的商品. 如今的货币系统有n种货币,相应面值为val[1],val[2]-val[n]. 然后他身上每种货币有num[i]个. John必须付给售货员>=m的金钱, 然后售货员会用最少的货币数量找钱给John. 问你John的交易过程中, 他给售货员的货币数目+售货员找钱给他的货币数目 的和最小值是多少? 分析: 本题与POJ 1252类型: http://blog.csdn.net/u013480600

混合三种背包问题(背包九讲)

问题: 如果将P01.P02.P03混合起来.也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包).应该怎么求解呢? 01背包与完全背包的混合: 考虑到在P01和P02中给出的伪代码只有一处不同,故如果只有两类物品:一类物品只能取一次,另一类物品可以取无限次,那么只需在对每个物品应用转移方程时,根据物品的类别选用顺序或逆序的循环即可,复杂度是O(VN).伪代码如下: for i=1..N if 第i件物品属于01背包 for v

HDU2191_悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(背包/多重背包)

解题报告 题目传送门 题意: 中文不多说; 思路: 基础多重背包,每个物品有多个可以选,转换成01背包解. #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 using namespace std; int main() { int t,i,j,n,m,v,p,h,cc,w[1010],c[1010],dp[1010]; scanf("%d",&

多重背包转换成完全背包和01背包

void CompletePack(int cost,int weight)   多重背包 { for(int i=cost;i<=m;i++) dp[i]=max(dp[i],dp[i-cost]+weight); } void ZeroOnePack(int cost,int weight)    01背包 { for(int i=m;i>=cost;i--) dp[i]=max(dp[i],dp[i-cost]+weight); } void MultiplyPack(int cost,

动态规划之背包问题-01背包+完全背包+多重背包

01背包 有n种不同的物品,每种物品分别有各自的体积 v[i],价值 w[i]  现给一个容量为V的背包,问这个背包最多可装下多少价值的物品. 1 for(int i = 1; i <= n; i++) 2 for(int j = V; j >= v[i]; j--) 3 dp[j] = max(dp[j], dp[j-v[i]]+w[i]); //dp[V]为所求 完全背包 01背包每种物品只能取一个, 完全背包即物品不记件数,可取多件. 1 for(int i = 1; i <= n

hdoj 1203 I NEED A OFFER! 【另类01背包】【概率背包】

题意:... 策略:动态规划. 因为是求至少能得到一个offer的概率,那我们可以反着求,求得不到一个offer的概率,最后用1减去就好了. 代码: #include<string.h> #include<stdio.h> double dp[10010]; struct node{ int a; double b; }s[10010]; int main() { int n, m, i, j; while(scanf("%d%d", &n, &

nyoj 860 又见01背包 【另类01背包】

分析: 首先这道题不能当做普通的01背包问题,因为W <= 10^9,开不了,那么大的数组,肯定有其他的思路,观察一下我们知道价值v小的很,最大100, 那我们就可以利用这一点,拿价值 之和作为原来的质量之和, 但是有一点要注意:因为题意是要在质量不超过W的范围内,找出最大的价值,我们现在是以最大的价值求质量,那么仔细分析一下,我们就能想明白,要以某价值i的背包存放尽量小的质量,这样反过来分析一下就可以知道,较小的质量有个较大的价值序号,这样完全满足题意了, 最后还有一点,就是价值背包的每一个(

nyoj 311-完全背包 (动态规划, 完全背包)

311-完全背包 内存限制:64MB 时间限制:4000ms Special Judge: No accepted:5 submit:7 题目描述: 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少.如果不能恰好装满背包,输出NO 输入描述: 第一行: N 表示有多少组测试数据(N<7). 接下来每组测试数

poj 3260 The Fewest Coins 多重背包+完全背包

题目链接:http://poj.org/problem?id=3260 给店家的钱是多重背包 dp[] 店家的找钱是完全背包 dp2[] 然后最后 其中i表示多给了多少钱 也就是需要找回多少钱 int ans = INF; ans = min(ans, dp[m+i] + dp2[i]); 是一个比较简单的思路 神坑题 看到每种货币的面值不大于120 我就觉得找钱一定不会超过119块钱结果wa到死 后来才发现不是的啊 之所以我有这种思维定式是因为现实生活中有1块钱这种货币单位 考虑一种极限的情况