diff --git a/codes/ruby/chapter_greedy/coin_change_greedy.rb b/codes/ruby/chapter_greedy/coin_change_greedy.rb new file mode 100644 index 000000000..7882b44b1 --- /dev/null +++ b/codes/ruby/chapter_greedy/coin_change_greedy.rb @@ -0,0 +1,50 @@ +=begin +File: coin_change_greedy.rb +Created Time: 2024-05-07 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 零钱兑换:贪心 ### +def coin_change_greedy(coins, amt) + # 假设 coins 列表有序 + i = coins.length - 1 + count = 0 + # 循环进行贪心选择,直到无剩余金额 + while amt > 0 + # 找到小于且最接近剩余金额的硬币 + while i > 0 && coins[i] > amt + i -= 1 + end + # 选择 coins[i] + amt -= coins[i] + count += 1 + end + # 若未找到可行方案, 则返回 -1 + amt == 0 ? count : -1 +end + +### Driver Code ### +if __FILE__ == $0 + # 贪心:能够保证找到全局最优解 + coins = [1, 5, 10, 20, 50, 100] + amt = 186 + res = coin_change_greedy(coins, amt) + puts "\ncoins = #{coins}, amt = #{amt}" + puts "凑到 #{amt} 所需的最少硬币数量为 #{res}" + + # 贪心:无法保证找到全局最优解 + coins = [1, 20, 50] + amt = 60 + res = coin_change_greedy(coins, amt) + puts "\ncoins = #{coins}, amt = #{amt}" + puts "凑到 #{amt} 所需的最少硬币数量为 #{res}" + puts "实际上需要的最少数量为 3 , 即 20 + 20 + 20" + + # 贪心:无法保证找到全局最优解 + coins = [1, 49, 50] + amt = 98 + res = coin_change_greedy(coins, amt) + puts "\ncoins = #{coins}, amt = #{amt}" + puts "凑到 #{amt} 所需的最少硬币数量为 #{res}" + puts "实际上需要的最少数量为 2 , 即 49 + 49" +end diff --git a/codes/ruby/chapter_greedy/fractional_knapsack.rb b/codes/ruby/chapter_greedy/fractional_knapsack.rb new file mode 100644 index 000000000..5790f278d --- /dev/null +++ b/codes/ruby/chapter_greedy/fractional_knapsack.rb @@ -0,0 +1,51 @@ +=begin +File: fractional_knapsack.rb +Created Time: 2024-05-07 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 物品 ### +class Item + attr_accessor :w # 物品重量 + attr_accessor :v # 物品价值 + + def initialize(w, v) + @w = w + @v = v + end +end + +### 分数背包:贪心 ### +def fractional_knapsack(wgt, val, cap) + # 创建物品列表,包含两个属性:重量,价值 + items = wgt.each_with_index.map { |w, i| Item.new(w, val[i]) } + # 按照单位价值 item.v / item.w 从高到低进行排序 + items.sort! { |a, b| (b.v.to_f / b.w) <=> (a.v.to_f / a.w) } + # 循环贪心选择 + res = 0 + for item in items + if item.w <= cap + # 若剩余容量充足,则将当前物品整个装进背包 + res += item.v + cap -= item.w + else + # 若剩余容量不足,则将当前物品的一部分装进背包 + res += (item.v.to_f / item.w) * cap + # 已无剩余容量,因此跳出循环 + break + end + end + res +end + +### Driver Code ### +if __FILE__ == $0 + wgt = [10, 20, 30, 40, 50] + val = [50, 120, 150, 210, 240] + cap = 50 + n = wgt.length + + # 贪心算法 + res = fractional_knapsack(wgt, val, cap) + puts "不超过背包容量的最大物品价值为 #{res}" +end diff --git a/codes/ruby/chapter_greedy/max_capacity.rb b/codes/ruby/chapter_greedy/max_capacity.rb new file mode 100644 index 000000000..f08a09c9e --- /dev/null +++ b/codes/ruby/chapter_greedy/max_capacity.rb @@ -0,0 +1,37 @@ +=begin +File: max_capacity.rb +Created Time: 2024-05-07 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 最大容量:贪心 ### +def max_capacity(ht) + # 初始化 i, j,使其分列数组两端 + i, j = 0, ht.length - 1 + # 初始最大容量为 0 + res = 0 + + # 循环贪心选择,直至两板相遇 + while i < j + # 更新最大容量 + cap = [ht[i], ht[j]].min * (j - i) + res = [res, cap].max + # 向内移动短板 + if ht[i] < ht[j] + i += 1 + else + j -= 1 + end + end + + res +end + +### Driver Code ### +if __FILE__ == $0 + ht = [3, 8, 5, 2, 7, 7, 3, 4] + + # 贪心算法 + res = max_capacity(ht) + puts "最大容量为 #{res}" +end diff --git a/codes/ruby/chapter_greedy/max_product_cutting.rb b/codes/ruby/chapter_greedy/max_product_cutting.rb new file mode 100644 index 000000000..cee752371 --- /dev/null +++ b/codes/ruby/chapter_greedy/max_product_cutting.rb @@ -0,0 +1,28 @@ +=begin +File: max_product_cutting.rb +Created Time: 2024-05-07 +Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) +=end + +### 最大切分乘积:贪心 ### +def max_product_cutting(n) + # 当 n <= 3 时,必须切分出一个 1 + return 1 * (n - 1) if n <= 3 + # 贪心地切分出 3 ,a 为 3 的个数,b 为余数 + a, b = n / 3, n % 3 + # 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 + return (3.pow(a - 1) * 2 * 2).to_i if b == 1 + # 当余数为 2 时,不做处理 + return (3.pow(a) * 2).to_i if b == 2 + # 当余数为 0 时,不做处理 + 3.pow(a).to_i +end + +### Driver Code ### +if __FILE__ == $0 + n = 58 + + # 贪心算法 + res = max_product_cutting(n) + puts "最大切分乘积为 #{res}" +end