程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 混合背包(多重背包+完全背包)—— POJ 3260

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

編輯:C++入門知識

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


 

 

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 V1, V2, ..., VN (1 ≤ Vi ≤ 120). Farmer John is carrying C1 coins of value V1, C2 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 V1, V2, ..., VN coins (V1, ...VN)
Line 3: N space-separated integers, respectively C1, C2, ..., 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 
#include 
#include 
#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
, min_s);
		else printf(-1
);
	}
	return 0;
}


 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved