├── .github └── workflows │ ├── cd.yml │ └── ci.yml ├── Cargo.toml ├── .gitignore ├── LICENSE ├── README.md └── src └── lib.rs /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | name: CD 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Set up Rust 14 | uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: stable 17 | override: true 18 | - name: Build project 19 | run: cargo build --release 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up Rust 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: stable 20 | override: true 21 | - name: Run tests 22 | run: cargo test 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "select-cells-in-grid-with-maximum-score" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Ali Ezzahn "] 6 | description = "A Rust library to solve the problem of selecting cells in a grid to maximize the score." 7 | repository = "https://github.com/aliezzahn/select-cells-in-grid-with-maximum-score" 8 | license = "MIT" 9 | keywords = ["grid", "dynamic-programming", "optimization"] 10 | categories = ["algorithms"] 11 | 12 | [dependencies] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | # RustRover 17 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 18 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 19 | # and can be added to the global gitignore or merged into this file. For a more nuclear 20 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 21 | #.idea/ 22 | 23 | # Added by cargo 24 | 25 | /target 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 aliezza hn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Select Cells in Grid with Maximum Score 2 | 3 | A Rust library to solve the problem of selecting cells in a grid to maximize the score. 4 | 5 | ![CI](https://github.com/aliezzahn/select-cells-in-grid-with-maximum-score/actions/workflows/ci.yml/badge.svg) 6 | ![CD](https://github.com/aliezzahn/select-cells-in-grid-with-maximum-score/actions/workflows/cd.yml/badge.svg) 7 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 8 | 9 | ## Problem Description 10 | 11 | Given a 2D grid of integers, the goal is to find the maximum score achievable by moving only right or down from the top-left corner to the bottom-right corner. The score is the sum of the values in the selected cells. 12 | 13 | ## Usage 14 | 15 | Add this library to your `Cargo.toml`: 16 | 17 | ```toml 18 | [dependencies] 19 | select-cells-in-grid-with-maximum-score = "0.1" 20 | ``` 21 | 22 | Then, use the `max_score` function in your code: 23 | 24 | ```rust 25 | use select_cells_in_grid_with_maximum_score::max_score; 26 | 27 | fn main() { 28 | let grid = vec![ 29 | vec![1, 2, 3], 30 | vec![4, 3, 2], 31 | vec![1, 1, 1], 32 | ]; 33 | let result = max_score(grid); 34 | println!("Maximum score: {}", result); // Output: Maximum score: 8 35 | } 36 | ``` 37 | 38 | ## Examples 39 | 40 | ### Example 1 41 | 42 | ```rust 43 | let grid = vec![ 44 | vec![1, 2, 3], 45 | vec![4, 3, 2], 46 | vec![1, 1, 1], 47 | ]; 48 | assert_eq!(max_score(grid), 8); 49 | ``` 50 | 51 | ### Example 2 52 | 53 | ```rust 54 | let grid = vec![ 55 | vec![8, 7, 6], 56 | vec![8, 3, 2], 57 | ]; 58 | assert_eq!(max_score(grid), 15); 59 | ``` 60 | 61 | ## Running Tests 62 | 63 | To run the tests, use the following command: 64 | 65 | ```bash 66 | cargo test 67 | ``` 68 | 69 | ## Contributing 70 | 71 | Contributions are welcome! Please open an issue or submit a pull request on [GitHub](https://github.com/aliezzahn/select-cells-in-grid-with-maximum-score). 72 | 73 | ## License 74 | 75 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 76 | 77 | --- 78 | 79 | ## Author 80 | 81 | - **Ali Ezzahn** 82 | - Email: [aliezzahn@gmail.com](mailto:aliezzahn@gmail.com) 83 | - GitHub: [aliezzahn](https://github.com/aliezzahn) 84 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | pub struct Solution; 4 | 5 | /// Solves the problem of selecting cells in a grid to maximize the score. 6 | /// 7 | /// Given a 2D grid of integers, the function calculates the maximum score 8 | /// achievable by moving only right or down from the top-left corner to the 9 | /// bottom-right corner. 10 | /// 11 | /// # Arguments 12 | /// 13 | /// * `grid` - A 2D vector of integers representing the grid. 14 | /// 15 | /// # Returns 16 | /// 17 | /// The maximum score as an `i32`. 18 | impl Solution { 19 | pub fn max_score(grid: Vec>) -> i32 { 20 | let n = grid.len(); 21 | let m = grid[0].len(); 22 | 23 | // Flatten the grid into a vector of (value, row, col) 24 | let mut values: Vec<(i32, usize, usize)> = Vec::new(); 25 | for i in 0..n { 26 | for j in 0..m { 27 | values.push((grid[i][j], i, j)); 28 | } 29 | } 30 | 31 | // Sort values in descending order 32 | values.sort_by(|a, b| b.0.cmp(&a.0)); 33 | 34 | // Initialize DP cache 35 | let mut dp: HashMap<(usize, usize), i32> = HashMap::new(); 36 | 37 | // Call the recursive function 38 | Self::recur(&values, 0, 0, &mut dp) 39 | } 40 | 41 | fn recur( 42 | values: &[(i32, usize, usize)], 43 | idx: usize, 44 | mask_row: usize, 45 | dp: &mut HashMap<(usize, usize), i32>, 46 | ) -> i32 { 47 | let n = values.len(); 48 | 49 | // Base case: if we've processed all cells 50 | if idx == n { 51 | return 0; 52 | } 53 | 54 | // Check if the result is already in the DP cache 55 | if let Some(&result) = dp.get(&(idx, mask_row)) { 56 | return result; 57 | } 58 | 59 | let (value, row, _) = values[idx]; 60 | let mut ans = 0; 61 | 62 | // Check if the row is already selected 63 | if (1 << row) & mask_row != 0 { 64 | // Row is already selected, skip this cell 65 | ans = Self::recur(values, idx + 1, mask_row, dp); 66 | } else { 67 | // Row is not selected, decide whether to select this cell or not 68 | let mut j = idx; 69 | while j < n && values[j].0 == values[idx].0 { 70 | j += 1; 71 | } 72 | 73 | // Option 1: Select this cell and mark the row as selected 74 | let ans1 = value + Self::recur(values, j, mask_row | (1 << row), dp); 75 | 76 | // Option 2: Skip this cell 77 | let ans2 = Self::recur(values, idx + 1, mask_row, dp); 78 | 79 | // Choose the maximum of the two options 80 | ans = ans1.max(ans2); 81 | } 82 | 83 | // Store the result in the DP cache 84 | dp.insert((idx, mask_row), ans); 85 | 86 | ans 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod tests { 92 | use super::*; 93 | 94 | #[test] 95 | fn test_max_score() { 96 | // Test case 1 97 | let grid1 = vec![ 98 | vec![1, 2, 3], 99 | vec![4, 3, 2], 100 | vec![1, 1, 1], 101 | ]; 102 | assert_eq!(Solution::max_score(grid1), 8); 103 | 104 | // Test case 2 105 | let grid2 = vec![ 106 | vec![8, 7, 6], 107 | vec![8, 3, 2], 108 | ]; 109 | assert_eq!(Solution::max_score(grid2), 15); 110 | } 111 | } --------------------------------------------------------------------------------