进制、货币

目录

一,关于进制的网络热梗

二,关于十进制的起源

三,货币组合问题

1,有限集合的最小不可表示的和

2,有限数列的最小不可表示的和

力扣 2952. 需要添加的硬币的最小数量

3,分金条问题

四,货币贪心问题

1,无限货币的贪心问题

2,有限货币的贪心问题

CSU 1926 使用最少的硬币

五,货币面额设计

1,面额的上下限

2,交易额颗粒度

3,货币组合问题

4,货币贪心问题

5,货币进制问题


一,关于进制的网络热梗

(1)世界上有10种人,一种懂二进制,另一种不懂。

PS:如果你有疑问,那你就是那个不懂二进制的

(2)这个世界上有三种人:会数数的和不会数数的。

PS:因为我就是那个不会数数的

(3)为什么程序员总是分不清万圣节和圣诞节?

PS:因为 Oct 31 == Dec 25

二,关于十进制的起源

PS:左边的是外星人,他的手指数量和地球人不同。

这个关于外星人和地球人的插画,是我的进制梗最爱,不仅幽默,而且有深度。

这里揭示了2个重要事实,第一,人类使用十进制是因为有十个手指头,第二,every base is base 10

三,货币组合问题

1,有限集合的最小不可表示的和

(1)问题

给定一个由正整数构成的有限集合,求最小的正整数x,使得x不是该集合的任意子集的所有数之和。

例如,对于集合{1,2,5,6},x=4是最小的不可表示为子集和的正整数。

(2)思路

首先我们把集合转化成一个递增的数列,核心思路是从前往后的归纳法,但是如何提炼命题呢?

对于任意集合A,可以表示的和的范围最多是从1到S(A)的闭区间,S(A)是A中所有元素的和。

在这个前提下,多试几个例子,观察规律,我们就能得到如下的核心猜想。

(3)命题P(n)

n个数组成的递增数列,最小不可表示的和一定等于左边若干个数的和+1

(4)第二数学归纳法

如果当n=1,2,3...k时,P(n)都成立,那么P(k+1)成立吗?

好像很难直接推出来。

(5)加强数学归纳法

我们把命题P变成加强命题Q:

n个数组成的递增数列,一定可以分成左右2个部分(2个都可能为空),最小不可表示的和等于左边所有数的和+1,且右边所有数都大于这个数。

对于Q,利用第二数学归纳法很容易证明。

于是我们就用加强数学归纳法证明了P。

(6)如何有效求出最小不可表示的和

其实还是需要用Q,因为P太弱了。

只需要找到第一个满足,一个数比前面所有数的和+1更大,那就找到了答案。

2,有限数列的最小不可表示的和

假如给定的数中有重复的,思路和结论不变。

力扣 2952. 需要添加的硬币的最小数量

给你一个下标从 开始的整数数组 coins,表示可用的硬币的面值,以及一个整数 target 。

如果存在某个 coins 的子序列总和为 x,那么整数 x 就是一个 可取得的金额 

返回需要添加到数组中的 任意面值 硬币的 最小数量 ,使范围 [1, target] 内的每个整数都属于 可取得的金额 。

数组的 子序列 是通过删除原始数组的一些(可能不删除)元素而形成的新的 非空 数组,删除过程不会改变剩余元素的相对位置。

示例 1:

输入:coins = [1,4,10], target = 19
输出:2
解释:需要添加面值为 2 和 8 的硬币各一枚,得到硬币数组 [1,2,4,8,10] 。
可以证明从 1 到 19 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 2 。

示例 2:

输入:coins = [1,4,10,5,7,19], target = 19
输出:1
解释:只需要添加一枚面值为 2 的硬币,得到硬币数组 [1,2,4,5,7,10,19] 。
可以证明从 1 到 19 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 1 。

示例 3:

输入:coins = [1,1,1], target = 20
输出:3
解释:
需要添加面值为 4 、8 和 16 的硬币各一枚,得到硬币数组 [1,1,1,4,8,16] 。 
可以证明从 1 到 20 的所有整数都可由数组中的硬币组合得到,且需要添加到数组中的硬币数目最小为 3 。

提示:

  • 1 <= target <= 105
  • 1 <= coins.length <= 105
  • 1 <= coins[i] <= target
class Solution {
public:
	int minimumAddedCoins(vector<int>& coins, int target) {
		sort(coins.begin(), coins.end());
		coins.push_back(target + 1);
		int s = 0, ans = 0;
		for (auto x : coins) {
			while (x > s + 1) {
				ans++;
				s += s + 1;
			}
			s += x;
			if (s >= target)return ans;
		}
		return -1;
	}
};

3,分金条问题

假设你是金主爸爸,你要雇一个人来给你打工一周,并且每天付他的报酬必须是一样的。

你手里有1根金条,还有1把无比锋利的可以切开金条的刀,但是你只能切2刀。

你要怎么切,怎么分配,才能保证每天付给工人的报酬是一样的呢?

答案:

按照1/7 2/7 4/7分成3段。

四,货币贪心问题

1,无限货币的贪心问题

问题:当前有面值分别为2角5分,1角,5分,1分的硬币,请给出找n分钱的最佳方案(要求找出的硬币数目最少)。

解析:

有25分,10分,5分,1分的,那么1分的肯定有n%5个,问题归结为5分,2分,1分的问题。

2个1分不如1个2分,所以1分最多1个, 3个2分不如1个5分和1个1分,所以2分最多2个。

只有6种情况,除掉1个1分2个2分的情况有5种情况,按照n%5直接对应就是唯一的最优解。

#include<iostream>
using namespace std;

int main()
{
	int n ;
	cout << "请输入多少分\n";
	cin >> n;
	if (n > 0)		//25,10,5,1
	{
		cout << "1分的要" << n % 5 << "个";		
		n = n / 5;		//5,2,1
		int m = n % 5;
		int a1=0, a2=0;
		if (m == 1)a1 = 1;
		if (m == 2)a2 = 0;
		if (m == 3)a1 = a2 = 1;
		if (m == 4)a2 = 2;
		cout << "\n5分的要" << a1 << "个\n1角的要"<<a2<<"个\n2角5分的要"<<n/5<<"个";
	}
	system("pause>nul");
	return 0;
}

2,有限货币的贪心问题

CSU 1926 使用最少的硬币

题目:

Description

在小X生活的国家里,很多面额都有硬币。小X的存钱罐里有四种硬币,分别是5元的、10元的、20元的和50元。当他要付钱时,总是希望使用的硬币数量最少。现在告诉你小X拥有的四种硬币的数量,请你帮小X求出最好的付款方案(可能方案不存在)。

Input

输入包含不超过10组数据。 每组数据由一行五个用空格隔开的整数A、B、C、D、S组成(0<=A,B,C,D<=1000000,1<=S<=10000000),分别表示小X拥有的5元硬币、10元硬币、20元硬币和50元硬币的个数,以及小X现在需要付的钱数(单位:元)。

Output

对于每组数据,如果小X无法付款,则输出一行一个整数-1;否则输出一行五个用空格隔开的整数a、b、c、d、s,分别表示付款方案中小X需要用掉的5元硬币、10元硬币、20元硬币和50元硬币的数量,以及小X需要花费的总硬币数。

Sample Input

1 2 3 4 35
1 2 3 4 567

Sample Output

1 1 1 0 3
-1

代码:

#include<iostream>
#include<algorithm>
using namespace std;
 
int main()
{
	int A, B, C, D, S;
	while (cin >> A >> B >> C >> D >> S)
	{
		if (S % 5 || S % 2 && A == 0)
		{
			cout << -1 << endl;
			continue;
		}
		S /= 5;  //1,2,4,10
		int a, b, c, d, s;
		if (A > S % 2 + 1 || B > 0)//贪心
		{
			d = min(S / 10, D), S -= d * 10;
			c = min(S / 4, C), S -= c * 4;
			b = min(S / 2, B), S -= b * 2;
			a = min(S, A), S -= a;
			s = a + b + c + d;
			if (S)cout << -1 << endl;
			else cout << a << " " << b << " " << c << " " << d << " " << s << endl;
			continue;
		}
		a = S % 2, S /= 2;//2,5
		if (S % 2 && D == 0)
		{
			cout << -1 << endl;
			continue;
		}
		d = min((S-S%2*5) / 10, (D - S % 2) / 2) * 2 + S % 2, S -= d * 5;
		c = min(S / 2, C), S -= c * 2;
		b = 0;
		s = a + b + c + d;
		if (S)cout << -1 << endl;
		else cout << a << " " << b << " " << c << " " << d << " " << s << endl;
	}
	return 0;
}

五,货币面额设计

我们不讨论防伪。工艺。文化艺术等等,只讨论面额(纯数字)。

面额设计里面的学问,比一般人想象的多的多。

1,面额的上下限

面额的上下限,取决于购买力,太小了没意义,太大了也不是很方便。

2,交易额颗粒度

假设所有的交易都是某个数额x的整数倍,那么x是多少?

对于我们来说,x就是一分钱。

实际情况可能更复杂,暂且这么理解吧。比如,我们的交易可以是,我每天给你0.3分,那我实际上可以每天给你打一个0.3分的欠条,凑足一定数量随时可以来找我折算。这些可以理解为虚拟交易,真实交易还是一分钱的整数倍。

那么,必须所有货币都是x的整数倍吗?为什么?

3,货币组合问题

如果要让任何数额的交易,都可以直接付钱,不需要找钱,怎么设计面额?

这个问题有一个暴力解,只要有x就行,因为x的数量是无限的,而所有交易都是x的倍数,所以可以只用x完成付钱,不需要找钱。

然而,有一个现实问题,只用x付钱,数量可能太多,所以一定需要组合付款。

很容易首先想到,要想满足多种付款金额,且用的货币数量较少(无论是否允许找钱),一定是所有货币都是x的整数倍是最优的

进一步地,考虑直接付钱不找钱,使用货币数量尽可能少,货币的整体分布应该是接近等比数列

4,货币贪心问题

为什么我们的货币面额是1,2,5,10,20,50,100?换成1,4,5,10,40,50,100行不行?

这是肯定不行的。1,2,5,10,20,50,100用贪心可以得到最优解,而1,4,5,10,40,50,100则不行。

5,货币进制问题

货币面额按照十进制去设计,更方便计算。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值