From 9d56622c7500e9b8c760bcb50c85cc57aed3f7a1 Mon Sep 17 00:00:00 2001 From: Night Cruising <77157236+night-cruise@users.noreply.github.com> Date: Sat, 22 Jul 2023 20:35:57 +0800 Subject: [PATCH] feat: add rust codes for chapter greedy (#646) * feat: add rust codes for chapter greedy * Update max_product_cutting.rs --------- Co-authored-by: Yudong Jin --- codes/rust/Cargo.toml | 20 +++++++ .../rust/chapter_greedy/coin_change_greedy.rs | 54 +++++++++++++++++ .../chapter_greedy/fractional_knapsack.rs | 59 +++++++++++++++++++ codes/rust/chapter_greedy/max_capacity.rs | 36 +++++++++++ .../chapter_greedy/max_product_cutting.rs | 35 +++++++++++ 5 files changed, 204 insertions(+) create mode 100644 codes/rust/chapter_greedy/coin_change_greedy.rs create mode 100644 codes/rust/chapter_greedy/fractional_knapsack.rs create mode 100644 codes/rust/chapter_greedy/max_capacity.rs create mode 100644 codes/rust/chapter_greedy/max_product_cutting.rs diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index ab910f9a0..cd528c925 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -349,5 +349,25 @@ path = "chapter_divide_and_conquer/hanota.rs" name = "build_tree" path = "chapter_divide_and_conquer/build_tree.rs" +# Run Command: cargo run --bin coin_change_greedy +[[bin]] +name = "coin_change_greedy" +path = "chapter_greedy/coin_change_greedy.rs" + +# Run Command: cargo run --bin fractional_knapsack +[[bin]] +name = "fractional_knapsack" +path = "chapter_greedy/fractional_knapsack.rs" + +# Run Command: cargo run --bin max_capacity +[[bin]] +name = "max_capacity" +path = "chapter_greedy/max_capacity.rs" + +# Run Command: cargo run --bin max_product_cutting +[[bin]] +name = "max_product_cutting" +path = "chapter_greedy/max_product_cutting.rs" + [dependencies] rand = "0.8.5" \ No newline at end of file diff --git a/codes/rust/chapter_greedy/coin_change_greedy.rs b/codes/rust/chapter_greedy/coin_change_greedy.rs new file mode 100644 index 000000000..b4bfa63f2 --- /dev/null +++ b/codes/rust/chapter_greedy/coin_change_greedy.rs @@ -0,0 +1,54 @@ +/* + * File: coin_change_greedy.rs + * Created Time: 2023-07-22 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 零钱兑换:贪心 */ +fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { + // 假设 coins 列表有序 + let mut i = coins.len() - 1; + let mut count = 0; + // 循环进行贪心选择,直到无剩余金额 + while amt > 0 { + // 找到小于且最接近剩余金额的硬币 + while coins[i] > amt { + i -= 1; + } + // 选择 coins[i] + amt -= coins[i]; + count += 1; + } + // 若未找到可行方案,则返回 -1 + if amt == 0 { + count + } else { + -1 + } +} + +/* Driver Code */ +fn main() { + // 贪心:能够保证找到全局最优解 + let coins = [1, 5, 10, 20, 50, 100]; + let amt = 186; + let res = coin_change_greedy(&coins, amt); + println!("\ncoins = {:?}, amt = {}", coins, amt); + println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + + // 贪心:无法保证找到全局最优解 + let coins = [1, 20, 50]; + let amt = 60; + let res = coin_change_greedy(&coins, amt); + println!("\ncoins = {:?}, amt = {}", coins, amt); + println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + println!("实际上需要的最少数量为 3 ,即 20 + 20 + 20"); + + // 贪心:无法保证找到全局最优解 + let coins = [1, 49, 50]; + let amt = 98; + let res = coin_change_greedy(&coins, amt); + println!("\ncoins = {:?}, amt = {}", coins, amt); + println!("凑到 {} 所需的最少硬币数量为 {}", amt, res); + println!("实际上需要的最少数量为 2 ,即 49 + 49"); +} \ No newline at end of file diff --git a/codes/rust/chapter_greedy/fractional_knapsack.rs b/codes/rust/chapter_greedy/fractional_knapsack.rs new file mode 100644 index 000000000..13754ae4f --- /dev/null +++ b/codes/rust/chapter_greedy/fractional_knapsack.rs @@ -0,0 +1,59 @@ +/* + * File: coin_change_greedy.rs + * Created Time: 2023-07-22 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 物品 */ +struct Item { + w: i32, // 物品重量 + v: i32, // 物品价值 +} + +impl Item { + fn new(w: i32, v: i32) -> Self { + Self { w, v } + } +} + +/* 分数背包:贪心 */ +fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { + // 创建物品列表,包含两个属性:重量、价值 + let mut items = wgt + .iter() + .zip(val.iter()) + .map(|(&w, &v)| Item::new(w, v)) + .collect::>(); + // 按照单位价值 item.v / item.w 从高到低进行排序 + items.sort_by(|a, b| { + (b.v as f64 / b.w as f64) + .partial_cmp(&(a.v as f64 / a.w as f64)) + .unwrap() + }); + // 循环贪心选择 + let mut res = 0.0; + for item in &items { + if item.w <= cap { + // 若剩余容量充足,则将当前物品整个装进背包 + res += item.v as f64; + cap -= item.w; + } else { + // 若剩余容量不足,则将当前物品的一部分装进背包 + res += item.v as f64 / item.w as f64 * cap as f64; + // 已无剩余容量,因此跳出循环 + break; + } + } + res +} + +/* Driver Code */ +fn main() { + let wgt = [10, 20, 30, 40, 50]; + let val = [50, 120, 150, 210, 240]; + let cap = 50; + + // 贪心算法 + let res = fractional_knapsack(&wgt, &val, cap); + println!("不超过背包容量的最大物品价值为 {}", res); +} \ No newline at end of file diff --git a/codes/rust/chapter_greedy/max_capacity.rs b/codes/rust/chapter_greedy/max_capacity.rs new file mode 100644 index 000000000..4cfb17713 --- /dev/null +++ b/codes/rust/chapter_greedy/max_capacity.rs @@ -0,0 +1,36 @@ +/* + * File: coin_change_greedy.rs + * Created Time: 2023-07-22 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 最大容量:贪心 */ +fn max_capacity(ht: &[i32]) -> i32 { + // 初始化 i, j 分列数组两端 + let mut i = 0; + let mut j = ht.len() - 1; + // 初始最大容量为 0 + let mut res = 0; + // 循环贪心选择,直至两板相遇 + while i < j { + // 更新最大容量 + let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32; + res = std::cmp::max(res, cap); + // 向内移动短板 + if ht[i] < ht[j] { + i += 1; + } else { + j -= 1; + } + } + res +} + +/* Driver Code */ +fn main() { + let ht = [3, 8, 5, 2, 7, 7, 3, 4]; + + // 贪心算法 + let res = max_capacity(&ht); + println!("最大容量为 {}", res); +} \ No newline at end of file diff --git a/codes/rust/chapter_greedy/max_product_cutting.rs b/codes/rust/chapter_greedy/max_product_cutting.rs new file mode 100644 index 000000000..c8fe01240 --- /dev/null +++ b/codes/rust/chapter_greedy/max_product_cutting.rs @@ -0,0 +1,35 @@ +/* + * File: coin_change_greedy.rs + * Created Time: 2023-07-22 + * Author: night-cruise (2586447362@qq.com) + */ + +/* 最大切分乘积:贪心 */ +fn max_product_cutting(n: i32) -> i32 { + // 当 n <= 3 时,必须切分出一个 1 + if n <= 3 { + return 1 * (n - 1); + } + // 贪心地切分出 3 ,a 为 3 的个数,b 为余数 + let a = n / 3; + let b = n % 3; + if b == 1 { + // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 + 3_i32.pow(a as u32 - 1) * 2 * 2 + } else if b == 2 { + // 当余数为 2 时,不做处理 + 3_i32.pow(a as u32) * 2 + } else { + // 当余数为 0 时,不做处理 + 3_i32.pow(a as u32) + } +} + +/* Driver Code */ +fn main() { + let n = 58; + + // 贪心算法 + let res = max_product_cutting(n); + println!("最大切分乘积为 {}", res); +}