【问题标题】:programming puzzle : how to count number of bacteria that are alive?编程难题:如何计算活着的细菌数量?
【发布时间】:2019-09-11 00:56:34
【问题描述】:

最近,我遇到了一个有趣的编程难题,其中提到了一些很好的转折。在令我惊讶的问题下方,我只是想知道在以下情况下可能在 java 中的任何相关解决方案是否可行。

问题陈述: 有一个尺寸为 m*n 的网格,最初,一个细菌存在于网格的左下角单元格(m-1,0),所有其他单元格都是空的。每一秒后,网格中的每个细菌都会自我分裂,并将相邻(水平、垂直和对角线)细胞中的细菌计数增加 1 并死亡。

n-1秒后右下角的细胞(m-1,n-1)有多少细菌? 我参考了 https://www.codechef.com/problems/BGH17 但未能提交解决方案 下面是更多问题的图片

【问题讨论】:

  • 有一个明显的算法在 O(mnn) 中运行,我怀疑你能不能更快。
  • 它与背包有什么关系吗?看起来好像不需要 NP-anything 算法...
  • @AndreyTyukin 老实说,我不知道任何 NP 算法,所以认为它可能与背包有关,因为提供的限制和价值(只是一个疯狂的猜测)
  • @BhargavModi 不清楚 4 个相邻单元格的分裂分布是什么。每个细菌分成 2 个,一个水平,一个垂直,但是如果有空间,它总是在左右或伪随机的 50%,或者它不分成 2 个细胞,而是分成 4 个,或者什么......还有对细菌的限制每个细胞计数?
  • @spektre 它似乎划分到网格内的所有相邻单元格(最多 8 个)。

标签: java algorithm matrix data-structures grid


【解决方案1】:

起始情况只有最左边的0列有值。我们需要知道时间n-1之后最右边的列n-1的情况。这意味着我们只需要查看每一列一次:在时间 x 处查看 x 列。在时间 x 之后 x 列发生的事情不再重要。所以我们从左到右,将上一列的单元格相加:

                                                1
                                          1     8
                                    1     7    35
                              1     6    27   104
                        1     5    20    70   230
                  1     4    14    44   133   392
            1     3     9    25    69   189   518
      1     2     5    12    30    76   196   512
1     1     2     4     9    21    51   127   323   ...

您还会注意到最后一个单元格的结果仅受前一列中的两个单元格的影响,而前一列中的三个单元格影响,因此要计算最终结果,例如n=9的情况下,只需要计算这个三角形中的值:

                        1
                  1     4    14
            1     3     9    25    69
      1     2     5    12    30    76   196
1     1     2     4     9    21    51   127   323

无论网格有多高,我们只需要向上 n/2(向上取整)行。因此,我们必须计算的总和为 n2/4,如果 m

还请注意,我们不必一次存储所有这些值,因为我们从左到右逐列存储。所以我们只需要一个大小为 n/2 的一维数组,其中的当前值是这样转换的(例如上例中从第 4 列到第 5 列):

[4, 5, 3, 1]     (0)  ->  0 + 5 - 0 = 5
[9, 5, 3, 1]     (5)  ->  9 + 3 - 5 = 7
[9,12, 3, 1]     (7)  ->  12 + 1 - 7 = 6
[9,12, 9, 1]     (6)  ->  9 + 0 - 6 = 3
[9,12, 9, 4]     (3)  ->  4 + 0 - 3 = 1
[9,12, 9, 4, 1]  (1)  (additional value is always 1)

我们从左到右迭代值,将当前元素左右的值相加,减去一个初始化为 0 的临时变量,将结果存储在一个临时变量中,然后将其添加到当前元素。


所以理论上的时间复杂度是O(n2)或O(n.m),空间复杂度是O(n)或O(m),取较小者。实际上,步数为n2/4,所需空间为n/2。


我不会说 Java,但这里有一个简单的 JavaScript 代码 sn-p 应该很容易翻译:

function bacteria(m, n) {
    var sum = [1];
    for (var col = 1; col < n; col++) {
        var temp = 0;
        var height = Math.min(col + 1, n - col, m);
        if (height > sum.length) sum.push(0);
        for (var row = 0; row < height; row++) {
            var left = row > 0 ? sum[row - 1] : 0;
            var right = row < sum.length - 1 ? sum[row + 1] : 0;
            temp = left + right - temp;
            sum[row] += temp;
        }
    }
    return sum[0];
}
document.write(bacteria(9, 9));

【讨论】:

    【解决方案2】:

    嗯,我在 Online Hackerrank 测试中被问到这个问题,当时无法解决。 后来我确实尝试对其进行编码,这是 C++ 中的解决方案,

    long countBacteriasAtBottomRight(int m, int n){
    long grid[m][n];
    
    // Set all to 0, and only bottom left to 1
    for (int i=0; i<m; i++){
        for (int j=0; j<n; j++){
            grid[i][j] = 0;
        }
    }
    
    grid[m-1][0] = 1;
    
    // Start the cycle, do it for (n-1) times
    int time = n-1;
    vector<long> toBeUpdated;
    
    while (time--){
        cout << "\n\nTime: " << time;
    
        for (int i=0; i<m; i++){
            for (int j=0; j<n; j++){
    
                while (grid[i][j] > 0){
                    grid[i][j]--;
    
                    // upper left
                    if (i > 0 && j > 0){
                        toBeUpdated.push_back(i-1);
                        toBeUpdated.push_back(j-1);
                    }
    
                    // upper
                    if (i > 0){
                        toBeUpdated.push_back(i-1);
                        toBeUpdated.push_back(j);
                    }
    
                    // upper right
                    if (i > 0 && j < n-1){
                        toBeUpdated.push_back(i-1);
                        toBeUpdated.push_back(j+1);
                    }
    
                    // left
                    if (j > 0){
                        toBeUpdated.push_back(i);
                        toBeUpdated.push_back(j-1);
                    }
    
                    // bottom left
                    if (i < m-1 && j > 0){
                        toBeUpdated.push_back(i+1);
                        toBeUpdated.push_back(j-1);
                    }
    
                    // bottom
                    if (i < m-1){
                        toBeUpdated.push_back(i+1);
                        toBeUpdated.push_back(j);
                    }
    
                    // bottom right
                    if (i < m-1 && j < n-1){
                        toBeUpdated.push_back(i+1);
                        toBeUpdated.push_back(j+1);
                    }
    
                    // right
                    if (j < n-1){
                        toBeUpdated.push_back(i);
                        toBeUpdated.push_back(j+1);
                    }
                };
            }
        }
    
        // Update all other cells
        for (int k=0; k<toBeUpdated.size(); k+=2){          
            grid[toBeUpdated[k]][toBeUpdated[k+1]]++;
        }
    
        for (int i=0; i<m; i++){
            cout << endl;
            for (int j=0; j<n; j++)
                cout << grid[i][j] << " ";
        }
    
        // Clear the temp vector
        toBeUpdated.clear();
    };
    
    return grid[m-1][n-1];
    }
    

    【讨论】:

      【解决方案3】:
      import java.util.ArrayList;
      import java.util.List;
      import java.util.Scanner;
      import java.util.Stack;    
      
      public class BacteriaProblem {
            public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("Number of Rows: ");
              int m = sc.nextInt();
              System.out.println("Number of Columns: ");
              int n = sc.nextInt();
              int[][] input = new int[m][n];
              input[m - 1][0] = 1;
              Stack<String> stack = new Stack<>();
              stack.push(m - 1 + "~" + 0);
              reproduce(stack, input, n - 1);
      
              System.out.println("Value at Bottom Right corner after n-1 secs: " + input[m - 1][n - 1]);
            }
      
            private static void reproduce(Stack<String> stack, int[][] input, int times) {
              //exit condition
              if (times < 1) {
                return;
              }
      
              //bacteria after splitting
              List<String> children = new ArrayList<>();
      
              //reproduce all existing bacteria
              while (!stack.isEmpty()) {
                String[] coordinates = stack.pop().split("~");
                int x = Integer.parseInt(coordinates[0]);
                int y = Integer.parseInt(coordinates[1]);
      
      
                for (int i = -1; i <= 1; i++) {
                  for (int j = -1; j <= 1; j++) {
                    if (i == 0 && j == 0) continue;
                    split(input, x + i, y + j, children);
                  }
                }
                input[x][y]--;
              }
      
              //add all children to stack
              for (String coord : children) {
                stack.push(coord);
              }
      
              //reduce times by 1
              reproduce(stack, input, times - 1);
      
            }
      
            private static void split(int[][] input, int x, int y, List<String> children) {
              int m = input.length;
              int n = input[0].length;
      
              if (x >= 0 && x < m && y >= 0 && y < n) {
                input[x][y]++;
                children.add(x + "~" + y);
              }
            }
          }
      

      【讨论】:

        猜你喜欢
        • 2015-09-23
        • 2019-01-08
        • 2020-10-21
        • 1970-01-01
        • 2011-03-02
        • 1970-01-01
        • 2012-04-14
        • 1970-01-01
        • 2020-03-03
        相关资源
        最近更新 更多