***完全背包

最优货币组合算法
探讨了在给定六种不同面值货币的情况下,如何通过算法计算支付1至100金额所需的最少货币数量,并求出这些支付方式的平均值和最大值。
Euro Efficiency
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%lld & %llu
Appoint description: 

Description

On January 1st 2002, The Netherlands, and several other European countries abandoned their national currency in favour of the Euro. This changed the ease of paying, and not just internationally. 
A student buying a 68 guilder book before January 1st could pay for the book with one 50 guilder banknote and two 10 guilder banknotes, receiving two guilders in change. In short:50+10+10-1-1=68. Other ways of paying were: 50+25-5-1-1, or 100-25-5-1-1.Either way, there are always 5 units (banknotes or coins) involved in the payment process, and it 
could not be done with less than 5 units. 
Buying a 68 Euro book is easier these days: 50+20-2 = 68, so only 3 units are involved.This is no coincidence; in many other cases paying with euros is more efficient than paying with guilders. On average the Euro is more efficient. This has nothing to do, of course, with the value of the Euro, but with the units chosen. The units for guilders used to be: 1, 2.5, 5, 10, 25, 50,whereas the units for the Euro are: 1, 2, 5, 10, 20, 50. 
For this problem we restrict ourselves to amounts up to 100 cents. The Euro has coins with values 1, 2, 5, 10, 20, 50 eurocents. In paying an arbitrary amount in the range [1, 100] eurocents, on average 2.96 coins are involved, either as payment or as change. The Euro series is not optimal in this sense. With coins 1, 24, 34, 39, 46, 50 an amount of 68 cents can be paid using two coins.The average number of coins involved in paying an amount in the range [1, 100] is 2.52. 
Calculations with the latter series are more complex, however. That is, mental calculations.These calculations could easily be programmed in any mobile phone, which nearly everybody carries around nowadays. Preparing for the future, a committee of the European Central Bank is studying the efficiency of series of coins, to find the most efficient series for amounts up to 100 eurocents. They need your help. 
Write a program that, given a series of coins, calculates the average and maximum number of coins needed to pay any amount up to and including 100 cents. You may assume that both parties involved have sufficient numbers of any coin at their disposal. 

Input

The first line of the input contains the number of test cases. Each test case is described by 6 different positive integers on a single line: the values of the coins, in ascending order. The first number is always 1. The last number is less than 100. 

Output

For each test case the output is a single line containing first the average and then the maximum number of coins involved in paying an amount in the range [1, 100]. These values are separated by a space. As in the example, the average should always contain two digits behind the decimal point. The maximum is always an integer. 

Sample Input

3
1 2 5 10 20 50
1 24 34 39 46 50
1 2 3 7 19 72

Sample Output

2.96 5
2.52 3

2.80 4

题意:有6种面值的货币,保证最小面值是1.可加可减,求出分别组成1~100金额的最少货币数.

并求出它们的平均值和最大值.

分析:有负权的完全背包,下界开大,注意处理负权即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>
#include<algorithm>
using namespace std;
#define Inf 0xffffff
#define M 100*100+100+1//方案数最多为100种,可推出M
int p[7], f[M];
double sum;
int m, num, i, v, k;
main()
{
   scanf("%d",&num);
   while(num--)
   {
      for(i=1;i<=6;i++)
         scanf("%d",&p[i]);
      f[0] = 0;
      for(i=1;i<=M;i++)
         f[i] = Inf;
      for(i=1;i<=6;i++)//不存在负权的情况 
        for(v=p[i];v<=M;v++)
        f[v] =min(1+f[v-p[i]],f[v]);//凑成v所需的最少纸币数 
      for(i=1;i<=6;i++)
        for(v=M-p[i];v>=1;v--)//存在负权的情况 ,需要逆序 
        f[v]=min(1+f[v+p[i]],f[v]);//注意这里是加,可看做-(-a[i])
      sum = 0;
      m = 0;
      for(v=1;v<=100;v++)
      {
         sum+=f[v];
         m =max(m,f[v]);//所需的最多纸币数 
      }
      printf("%.2f %d\n",sum/100,m);
   }
   return 0;
}

### 原理 - **01背包**:01背包问题中,每件物品最多选1次,即对于每件物品,只有选或不选两种状态。核心在于在有限容量的背包中选择物品,使得总价值最大化[^3]。 - **完全背包**:完全背包问题里,每件物品可选无限次。同样是在有限容量的背包条件下,要找出物品的选择组合,让总价值达到最大[^3]。 ### 算法 - **01背包算法** - **贪心算法**:贪心选择性质指通过局部最优选择产生全局最优解。对于01背包,可按物品的价值与重量比(价值密度)降序排列物品,依次选择价值密度最高的物品放入背包,直至无法再放入,得到局部最优解。不过贪心算法不一定能得到全局最优解[^1]。 - **动态规划算法**:定义`dp[i][j]`表示前`i`个物品放入容量为`j`的背包中能获得的最大价值。状态转移方程为`dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i])` (当`j >= w[i]`时),其中`w[i]`是第`i`个物品的重量,`v[i]`是第`i`个物品的价值。在做01背包问题一维优化时,内层循环中背包应从最大容量开始逆序遍历,避免覆盖前面存入的数据。以下是一个01背包问题动态规划的代码示例: ```python def zero_one_knapsack(weights, values, capacity): n = len(weights) dp = [0] * (capacity + 1) for i in range(n): for j in range(capacity, weights[i] - 1, -1): dp[j] = max(dp[j], dp[j - weights[i]] + values[i]) return dp[capacity] ``` - **完全背包算法**:完全背包的动态规划算法与01背包类似,但内层循环是正序遍历。状态转移方程为`dp[i][j] = max(dp[i - 1][j], dp[i][j - w[i]] + v[i])`(当`j >= w[i]`时)。以下是完全背包问题动态规划的代码示例: ```python def complete_knapsack(weights, values, capacity): n = len(weights) dp = [0] * (capacity + 1) for i in range(n): for j in range(weights[i], capacity + 1): dp[j] = max(dp[j], dp[j - weights[i]] + values[i]) return dp[capacity] ``` ### 应用 - **01背包应用**:资源分配问题,如在一定预算下选择不同项目,每个项目有成本和收益,且每个项目只能选择一次;装箱问题,有不同大小和价值的物品,要在有限的箱子容量内选择物品使总价值最大等。 - **完全背包应用**:找零钱问题,有不同面值的硬币,每种硬币数量无限,要凑出一定金额;物品无限供应的采购问题,在一定资金限制下采购不同物品,每种物品可买多个,使采购物品的总价值最大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值