引言
在生活中,钢条和饼干看似风马牛不相及,但它们的分割与分发却隐藏着惊人的数学魅力。如何最大化利润?如何用有限的资源最大程度满足需求?这便是算法世界中的艺术。今天,我们来揭秘钢条切割与饼干分发的算法设计。本文不仅有趣,也能带你领略算法的美妙和工程师的智慧。
1.钢条切割
1.1题目描述
某公司的主营业务是切割整段钢条并出售,切割钢条的成本和损耗忽略不计。
该公司现有以下长度的钢条:
钢条长度/米 | 10 | 12 | 15 |
成本/百元 | 10 | 12 | 15 |
已知不同长度的钢条的出售价格:
钢条长度/米 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
售价/百元 |
1 |
5 |
8 |
9 |
10 |
17 |
17 |
20 |
24 |
24 |
- 假如你是该公司的工程师,试确定每条钢条的切割方式使盈利最大。
- 经过技术攻关,公司掌握了将钢条焊接的方法,且每次焊接所需成本为1百元,试确定钢条的焊接或/和切割方式使盈利最大。
1.2算法设计 (第一部分:不考虑焊接)
采用动态规划法。dp[i]
表示长度为 i
米钢条的最大收益。状态转移方程:
dp[i] = max(price[i], dp[i-j] + dp[j])
(1 ≤ j ≤ i)
其中 price[i]
为长度为 i
米钢条的售价。
1.3伪代码实现 (第一部分:不考虑焊接)
function max_profit_no_weld(prices, n): dp = array of size n+1, initialized to 0 for i from 1 to n: max_p = prices[i] for j from 1 to i: max_p = max(max_p, dp[i-j] + dp[j]) dp[i] = max_p return dp[n]
1.4算法设计 (第二部分:考虑焊接)
仍然采用动态规划。dp[i]
表示长度为 i
米钢条的最大收益,考虑焊接成本。状态转移方程更加复杂,需要考虑所有可能的切割和焊接组合:
dp[i] = max(price[i], max(dp[j] + dp[i-j] - 1, dp[j] + price[i-j] - 1, price[j] + dp[i-j] - 1))
(1 ≤ j ≤ i/2)
1.5伪代码实现 (第二部分:考虑焊接)
function max_profit_weld(prices, n): dp = array of size n+1, initialized to -infinity // Initialize with a very small value dp[0] = 0 for i from 1 to n: dp[i] = prices[i] // Initialize with no cut for j from 1 to i/2: dp[i] = max(dp[i], dp[j] + dp[i-j] - 1) dp[i] = max(dp[i], dp[j] + prices[i-j] - 1) dp[i] = max(dp[i], prices[j] + dp[i-j] - 1) return dp[n]
2.饼干分发
2.1题目描述
假设你是一个幼儿园园长,现在要给孩子们分发饼干。由于饼干数量有限,每个孩子都只能得到一块饼干。其中,孩子i所需的饼干大小为gi,饼干j的大小为sj,若sj≥gi则孩子能够吃饱。你的目标是尽可能喂饱更多数量的孩子,并输出这个最大数值。
示例1:你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,但饼干的尺寸都是1只能让胃口值是1的孩子满足,所以输出1。 输入:g=[1,2,3],s=[1,1] 输出:1 示例2:你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足,所以输出2。 输入:g =[1,2],s=[1,2,3] 输出:2 |
1.现有如下饼干和孩子,试求其输出。
第一组: g=[1 2 2 3 5 6 8 10] s=[1 1 2 2 4 5 5 6 7 8 9 10] 第二组: g=[12 5 8 1 5 3 7 5 8 6] s=[15 6 8 5 2 8 7 4 5 1 2 4 3 6] |
2.经过和孩子友好协商,孩子同意每个孩子可以有最多两块饼干,针对上述两组饼干和孩子试求能否喂饱更多孩子。
2.2算法设计 (第一部分:每个孩子一块饼干)
采用贪心算法。先对 g 和 s 排序,然后从最小的孩子开始,分配最小的满足条件的饼干。
2.3伪代码实现 (第一部分:每个孩子一块饼干)
function max_satisfied_children(g, s): sort g in ascending order sort s in ascending order count = 0 i = 0, j = 0 while i < length(g) and j < length(s): if s[j] >= g[i]: count = count + 1 i = i + 1 j = j + 1 else: j = j + 1 return count
2.4算法设计 (第二部分:每个孩子最多两块饼干)
仍然采用贪心算法,但需要修改分配策略。先尝试分配一块饼干,如果满足不了,再尝试分配两块。
2.5伪代码实现(第二部分:每个孩子最多两块饼干)
function max_satisfied_children_two(g, s): sort g in ascending order sort s in ascending order count = 0 i = 0, j = 0 while i < length(g) and j < length(s): if s[j] >= g[i]: count = count + 1 i = i + 1 j = j + 1 else: k = j + 1 if k < length(s) and s[j] + s[k] >= g[i]: count = count + 1 i = i + 1 j = k + 1 else: j = j + 1 return count
通过这两个问题的探讨,我们可以看到算法在解决实际问题中的强大能力。无论是在工业生产中的钢条切割问题,还是在日常生活中的饼干分发问题,算法都能提供高效且经济的解决方案。这些算法不仅体现了数学的精妙,也展示了工程师在解决实际问题时的智慧和创造力。
3.总结
本文探讨了两个经典的算法问题:钢条切割和饼干分发,展示了算法在解决实际问题中的强大能力和数学的魅力。这两个问题虽然看似简单,却涉及到了动态规划和贪心算法等重要的算法设计思想。
在钢条切割问题中,我们首先考虑了不考虑焊接的情况,通过动态规划的方法,计算出每种长度钢条的最大盈利切割方式。动态规划的核心在于状态转移方程的设计,它能够将问题分解为更小的子问题,并利用子问题的解来构建原问题的解。接着,我们考虑了焊接的情况,这使得问题变得更加复杂,因为我们需要考虑所有可能的切割和焊接组合。这个问题的解决同样依赖于动态规划,但状态转移方程更加复杂,需要考虑焊接成本。
在饼干分发问题中,我们采用了贪心算法来解决。贪心算法的关键在于每一步都做出局部最优的选择,希望这样的局部最优选择能够导致全局最优解。在每个孩子一块饼干的情况下,我们通过对孩子的需求和饼干的大小进行排序,然后从最小的孩子开始分配最小的满足条件的饼干。在每个孩子最多两块饼干的情况下,我们同样采用贪心算法,但需要修改分配策略,尝试分配一块饼干,如果满足不了,再尝试分配两块。
这两个问题的探讨不仅体现了数学的精妙,也展示了工程师在解决实际问题时的智慧和创造力。算法的应用不仅限于计算机科学领域,它们在工业生产、物流管理、资源分配等多个领域都有着广泛的应用。通过算法,我们可以更高效地利用资源,最大化利润,满足需求,这些都是算法在现代社会中不可或缺的价值。
总的来说,钢条切割和饼干分发问题不仅是算法学习的入门课题,也是理解算法如何解决实际问题的重要案例。它们教会我们如何将复杂问题分解为可管理的小问题,并通过巧妙的算法设计找到最优解。这些算法的应用不仅提高了效率,也为我们提供了解决问题的新思路,体现了算法之美。