求二維數組蓄水數

1、需求

接上一個需求:求一維數組蓄水數,如果數組是二維數組呢?

如果求得蓄水數呢?

比如這種情況:紅色的格子是能蓄水的格子,藍色的各自是牆, 也就是不能蓄水的格子

 

2、解題思路

其實對於這種題目,會很很多的難點,比如:

簡單低窪地帶,直接求蓄水數,上下左右  5 5 5 5, 那中間的3 是能蓄水的

比如:

比如這種:

       

以上這些圖形出現的時候,其實求解還是比較複雜的。

 

我提供的思路呢是:

如果這個二維數組,就是一個0-1矩陣的話,那麼求出蓄水數,還是挺容易的。比如:

整體思路:把0-1二維數組映射成爲一個最終的true-false數組。true的位置表示能蓄水。false的位置,表示不能蓄水。

顯然:最外層無論如何,都不能蓄水。

1、先把0-1二維數組映射成爲一個true-false數組:0的位置爲true,  1的位置爲false(這裏面的true中,還有部分是不可蓄水的,排除掉所有的不可蓄水的true,然後count一下所有的剩下的true就是這個0-1矩陣的蓄水數)

2、從外層往裏層遍歷,遍歷一次,就把最外層的所有的0都置位false

3、不停的重複“2”步驟,直到,再也不需要把任何的0置位false爲止

4、count一下還剩下的true有多少個,就是能蓄水的位置和數量

 

既然每個0-1數組的蓄水數都能求出來了,那麼把一個正常數組切分成一個多個0-1數組,是很簡單的事了,如果有對此不懂的同學,請去研究代碼的實現。

 

那整體思路:

1、先把一個正常的二維矩陣變成多個0-1二維矩陣

2、求出每個二維矩陣的蓄水數

3、把切分出來的所有二維矩陣的蓄水數相加就能求出總蓄水數。

 

3、具體代碼實現

package com.aura.funny.water;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 馬中華 https://blog.csdn.net/zhongqi2513
 * @Title: WaterMatrix02.java
 * @Package com.aura.funny.water
 * @ClassName: WaterMatrix02
 * @Description: 用來計算二維矩陣的蓄水量
 * @date 2016年1月27日 下午1:39:30
 */
public class WaterMatrix02 {

  // 矩陣行數
  public static final int MATRIX_ROW = 8;
  // 矩陣列寬
  public static final int MATRIX_COLUMN = 8;
  // 矩陣最大高度
  public static final int MATRIX_MAX_HEIGHT = 30;
  // 矩陣最小高度
  public static final int MATRIX_MIN_HEIGHT = 10;

  /**
   * @param args
   * @Title: main
   * @Description: 測試入口
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午4:35:22
   */
  public static void main(String[] args) {

    // 第一步:產生一個隨機矩陣
    int[][] matrix = provideMatrix();

	/*int[][] matrix = new int[][]{{9,9,9,9,9,9,9,9,9},
					{9,9,9,9,9,9,9,9,9},
					{9,9,2,2,2,2,2,9,9},
					{9,9,2,9,9,9,2,9,9},
					{9,9,2,9,2,9,2,9,9},
					{9,9,2,9,9,9,2,9,9},
					{9,9,2,2,2,2,2,9,9},
					{9,9,9,9,9,9,9,9,9},
					{9,9,9,9,9,9,9,9,9}
	};*/

    printMatrix(matrix);
    System.out.println("----------------------華麗麗分割線-----------------------------");

    // 總蓄水量
    int sumWater = 0;

    // 第二步:獲取該矩陣的所有0-1矩陣, 並打印顯示
    List<int[][]> oneZeroMatrixList = getOneZeroMatrixList(matrix);

    // 用來表示,是否已經開始產生蓄水
    boolean flag = false;
    for (int i = MATRIX_MIN_HEIGHT, size = oneZeroMatrixList.size(); i < size; i++) {
      int[][] oneZeroMatrix = oneZeroMatrixList.get(i);
      // 打印0-1矩陣
      printMatrix(oneZeroMatrix);
      // 求0-1矩陣的蓄水數
      int water = getWaterFromOneZeroMatrix(oneZeroMatrix);
      if(water != 0){
        flag = true;
      }

      System.out.println("第  " + (i + 1) + " 層的蓄水爲:" + water);
      System.out.println("-----------------------------------------------------------");

      // 如果當前這一層都不能蓄水,那麼上一層也一定不能蓄水
      if(flag && water == 0){
        System.out.println("再往上的每一層("+(i + 2) +" - "+ MATRIX_MAX_HEIGHT+"),都是蓄水數爲0,不必再計算");
        break;
      }
      sumWater += water;
    }

    // 第五步: 輸出結果
    System.out.println("\n" + "該二維矩陣蓄水量:" + sumWater);
  }

  /**
   * @return
   * @Title: provideMatrix
   * @Description: 這個方法用來產生一個隨機矩陣, 長寬高由以上四個屬性決定, 會等於邊界值
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午1:43:18
   */
  public static int[][] provideMatrix() {
    return provideMatrix(MATRIX_ROW, MATRIX_COLUMN, MATRIX_MIN_HEIGHT, MATRIX_MAX_HEIGHT);
  }

  public static int[][] provideMatrix(int row, int column, int min, int max) {
    int[][] sourceMatrix = new int[row][column];
    for (int i = 0; i < row; i++) {
      for (int j = 0; j < column; j++) {
        sourceMatrix[i][j] = randomNumber(min, max);
      }
    }
    return sourceMatrix;
  }

  /**
   * @param min
   * @param max
   * @return
   * @Title: randomNumber
   * @Description: 用來產生一個區間內的隨機整數
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午1:45:36
   */
  public static int randomNumber(int min, int max) {
    if (min < max) {
      return (int) (Math.random() * (max - min + 1) + min);
    } else if (min == max) {
      return min;
    } else {
      return randomNumber(max, min);
    }
  }

  /**
   * @Title: printMatrix
   * @Description: 打印二維矩陣
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午4:19:15
   */
  public static void printMatrix(int[][] matrix) {
    for (int i = 0, size = matrix.length; i < size; i++) {
      for (int j = 0, length = matrix[0].length; j < length; j++) {
        System.out.print(matrix[i][j] + "\t");
      }
      System.out.println();
    }
  }

  public static void printBooleanMatrix(boolean[][] matrix) {
    for (int i = 0, size = matrix.length; i < size; i++) {
      for (int j = 0, length = matrix[0].length; j < length; j++) {
        System.out.print(matrix[i][j] + "\t");
      }
      System.out.println();
    }
  }

  /**
   * @param oneZeroMatrix
   * @return
   * @Title: copyOneZeroMatrixToBoolean
   * @Description: 矩陣轉化:把0-1矩陣轉換成true-false矩陣(0-true, 1-false)
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午6:00:09
   */
  public static boolean[][] copyOneZeroMatrixToBoolean(int[][] oneZeroMatrix) {
    boolean[][] booleanMatrix = new boolean[oneZeroMatrix.length][oneZeroMatrix[0].length];
    for (int i = 0, size = oneZeroMatrix.length; i < size; i++) {
      for (int j = 0, length = oneZeroMatrix[0].length; j < length; j++) {
        if (oneZeroMatrix[i][j] == 0) {
          booleanMatrix[i][j] = true;
        } else {
          booleanMatrix[i][j] = false;
        }
      }
    }
    return booleanMatrix;
  }

  /**
   * @return
   * @Title: getOneZeroMatrixList
   * @Description: 把一個隨機矩陣切分成最大高度個數的0-1矩陣
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午4:24:17
   */
  public static List<int[][]> getOneZeroMatrixList(int[][] matrix) {
    int max = getMaxFromMatrix(matrix);
    List<int[][]> oneZeroMatrixList = new ArrayList<int[][]>();
    for (int k = 0; k < max; k++) {
      int[][] oneZeroMatrix = new int[matrix.length][matrix[0].length];
      // 此處開始循環按層切割矩陣
      for (int i = 0, size = matrix.length; i < size; i++) {
        for (int j = 0, length = matrix[0].length; j < length; j++) {
          if (matrix[i][j] > 0) {
            oneZeroMatrix[i][j] = 1;
            matrix[i][j] -= 1;
          } else {
            oneZeroMatrix[i][j] = 0;
          }
        }
      }
      oneZeroMatrixList.add(oneZeroMatrix);
    }
    return oneZeroMatrixList;
  }

  /**
   * @return
   * @Title: getMaxFromMatrix
   * @Description: 獲取矩陣最大值
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午4:25:43
   */
  public static int getMaxFromMatrix(int[][] matrix) {
    int max = 0;
    for (int i = 0, size = matrix.length; i < size; i++) {
      for (int j = 0, length = matrix[0].length; j < length; j++) {
        if (matrix[i][j] >= max) {
          max = matrix[i][j];
        }
      }
    }
    return max;
  }

  public static int getMinFromMatrix(int[][] matrix) {
    int max = matrix[0][0];
    for (int i = 0, size = matrix.length; i < size; i++) {
      for (int j = 0, length = matrix[0].length; j < length; j++) {
        if (matrix[i][j] <= max) {
          max = matrix[i][j];
        }
      }
    }
    return max;
  }

  /**
   * @Title: getWaterFromOneZeroMatrix
   * @Description: 從一個0-1矩陣中獲取所有被1包圍的0的個數,即是求取該0-1矩陣的蓄水量
   * @author 馬中華 https://blog.csdn.net/zhongqi2513
   * @date 2016年1月27日 下午4:38:36
   */
  public static int getWaterFromOneZeroMatrix(int[][] oneZeroMatrix) {
    // 從 oneZeroMatrix 賦值一個 booleanMatrix
    boolean[][] booleanMatrix = copyOneZeroMatrixToBoolean(oneZeroMatrix);

    int maxX = oneZeroMatrix[0].length;
    int maxY = oneZeroMatrix.length;

    // 給左右邊界0值置 false
    for (int i = 0; i < maxX; i++) {
      booleanMatrix[0][i] = false;
      booleanMatrix[maxY - 1][i] = false;
    }
    // 給上下邊界0值置 false
    for (int j = 0; j < maxY; j++) {
      booleanMatrix[j][0] = false;
      booleanMatrix[j][maxX - 1] = false;
    }

    int changeNumber = 1;

    while (changeNumber != 0) {
      System.out.println("執行改值次數: " + changeNumber);
      changeNumber = setFalseArea(oneZeroMatrix, booleanMatrix, maxX, maxY);
    }

    return countTrueFromMatrix(booleanMatrix);
  }

  /**
   * 描述: 每次循環設置false值, 只要有值還可以設置成false,那麼就要執行下去,如果返回值 changeNumber == 0 , 那麼表示已經執行完畢
   * 作者: 馬中華 https://blog.csdn.net/zhongqi2513
   * 日期 : 2016年1月27日 下午11:21:28
   *
   * @param oneZeroMatrix
   * @param booleanMatrix
   * @param maxX
   * @param maxY
   * @return
   */
  public static int setFalseArea(int[][] oneZeroMatrix, boolean[][] booleanMatrix, int maxX, int maxY) {
    int changeNumber = 0;
    for (int i = 1; i < maxY - 1; i++) {
      for (int j = 1; j < maxX - 1; j++) {
        if (booleanMatrix[i][j] && isZeroAndFalse(oneZeroMatrix, booleanMatrix, i, j)) {
          changeNumber++;
          booleanMatrix[i][j] = false;
        }
      }
    }
    return changeNumber;
  }

  /**
   * 描述: 用來判斷該點是否與
   * 作者: 馬中華 https://blog.csdn.net/zhongqi2513
   * 日期 : 2016年1月27日 下午10:50:24
   *
   * @return
   */
  public static boolean isZeroAndFalse(int[][] oneZeroMatrix, boolean[][] booleanMatrix, int x, int y) {
    if (oneZeroMatrix[x - 1][y] == 0 && !booleanMatrix[x - 1][y]) { // 左
      return true;
    }
    if (oneZeroMatrix[x + 1][y] == 0 && !booleanMatrix[x + 1][y]) { // 右
      return true;
    }
    if (oneZeroMatrix[x][y - 1] == 0 && !booleanMatrix[x][y - 1]) { // 上
      return true;
    }
    if (oneZeroMatrix[x][y + 1] == 0 && !booleanMatrix[x][y + 1]) { // 下
      return true;
    }
    return false;
  }

  /**
   * 描述: count matrix 中 true 的個數,
   * 作者: 馬中華 https://blog.csdn.net/zhongqi2513
   * 日期 : 2016年1月27日 下午9:47:09
   *
   * @param booleanMatrix
   * @return
   */
  public static int countTrueFromMatrix(boolean[][] booleanMatrix) {
    int falseCounts = 0;
    for (int i = 0, size = booleanMatrix.length; i < size; i++) {
      for (int j = 0, length = booleanMatrix[0].length; j < length; j++) {
        if (booleanMatrix[i][j]) {
          falseCounts++;
        }
      }
    }
    return falseCounts;
  }

}

 

4、執行結果

21	18	15	26	17	11	27	29	
18	21	16	11	26	23	29	20	
13	28	14	26	13	22	27	23	
16	13	27	23	18	22	15	21	
16	18	28	14	10	30	17	26	
17	12	16	10	11	14	19	15	
16	24	25	21	14	18	14	18	
28	16	22	15	26	21	12	22	
----------------------華麗麗分割線-----------------------------
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	0	1	1	1	
1	1	1	0	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
執行改值次數: 1
第  11 層的蓄水爲:2
-----------------------------------------------------------
1	1	1	1	1	0	1	1	
1	1	1	0	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	0	1	1	1	
1	1	1	0	0	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
執行改值次數: 1
第  12 層的蓄水爲:4
-----------------------------------------------------------
1	1	1	1	1	0	1	1	
1	1	1	0	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	0	1	1	1	
1	0	1	0	0	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	0	1	
執行改值次數: 1
第  13 層的蓄水爲:5
-----------------------------------------------------------
1	1	1	1	1	0	1	1	
1	1	1	0	1	1	1	1	
0	1	1	1	0	1	1	1	
1	0	1	1	1	1	1	1	
1	1	1	1	0	1	1	1	
1	0	1	0	0	1	1	1	
1	1	1	1	1	1	1	1	
1	1	1	1	1	1	0	1	
執行改值次數: 1
第  14 層的蓄水爲:7
-----------------------------------------------------------
1	1	1	1	1	0	1	1	
1	1	1	0	1	1	1	1	
0	1	0	1	0	1	1	1	
1	0	1	1	1	1	1	1	
1	1	1	0	0	1	1	1	
1	0	1	0	0	0	1	1	
1	1	1	1	0	1	0	1	
1	1	1	1	1	1	0	1	
執行改值次數: 1
執行改值次數: 1
第  15 層的蓄水爲:11
-----------------------------------------------------------
1	1	0	1	1	0	1	1	
1	1	1	0	1	1	1	1	
0	1	0	1	0	1	1	1	
1	0	1	1	1	1	0	1	
1	1	1	0	0	1	1	1	
1	0	1	0	0	0	1	0	
1	1	1	1	0	1	0	1	
1	1	1	0	1	1	0	1	
執行改值次數: 1
執行改值次數: 1
第  16 層的蓄水爲:12
-----------------------------------------------------------
1	1	0	1	1	0	1	1	
1	1	0	0	1	1	1	1	
0	1	0	1	0	1	1	1	
0	0	1	1	1	1	0	1	
0	1	1	0	0	1	1	1	
1	0	0	0	0	0	1	0	
0	1	1	1	0	1	0	1	
1	0	1	0	1	1	0	1	
執行改值次數: 1
執行改值次數: 5
第  17 層的蓄水爲:10
-----------------------------------------------------------
1	1	0	1	0	0	1	1	
1	1	0	0	1	1	1	1	
0	1	0	1	0	1	1	1	
0	0	1	1	1	1	0	1	
0	1	1	0	0	1	0	1	
0	0	0	0	0	0	1	0	
0	1	1	1	0	1	0	1	
1	0	1	0	1	1	0	1	
執行改值次數: 1
執行改值次數: 11
執行改值次數: 2
第  18 層的蓄水爲:3
-----------------------------------------------------------
1	0	0	1	0	0	1	1	
0	1	0	0	1	1	1	1	
0	1	0	1	0	1	1	1	
0	0	1	1	0	1	0	1	
0	0	1	0	0	1	0	1	
0	0	0	0	0	0	1	0	
0	1	1	1	0	0	0	0	
1	0	1	0	1	1	0	1	
執行改值次數: 1
執行改值次數: 13
執行改值次數: 2
執行改值次數: 1
執行改值次數: 1
第  19 層的蓄水爲:2
-----------------------------------------------------------
1	0	0	1	0	0	1	1	
0	1	0	0	1	1	1	1	
0	1	0	1	0	1	1	1	
0	0	1	1	0	1	0	1	
0	0	1	0	0	1	0	1	
0	0	0	0	0	0	0	0	
0	1	1	1	0	0	0	0	
1	0	1	0	1	1	0	1	
執行改值次數: 1
執行改值次數: 14
執行改值次數: 3
執行改值次數: 2
執行改值次數: 1
第  20 層的蓄水爲:0
-----------------------------------------------------------
再往上的每一層(21 - 30),都是蓄水數爲0,不必再計算

該二維矩陣蓄水量:56

Process finished with exit code 0

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章