Java - 趣味题(1) --- 木桶效应

给你一个二维数组(比如是M*N的),把他们放入M*N的方格中,每个数字代表该方格的高度,这样就俯视就会形成凹凸不平,如果用这个形状存储水,凹的地方会有积水,请问它能存储多少水?
例如二维数组为:
9 9 9 9
3 0 0 9
7 8 9 6时,
答案是中间的0,0位置可以存储3(因为其外面最低是3,即“木桶效应”)个单位的水,
因此答案为3+3=6;

如何使用程序来计算存储的水的量呢?

源码:

import java.util.Scanner;

public class Cannikin { // 木桶

            static int M            = 0; // 行:有效范围[0,M)
            static int N            = 0; // 列:有效范围[0,N)
    final   static int GRID_HEIGHT  = 0; // 方格属性下标0:方格高度
    final   static int GRID_WATER   = 1; // 方格属性下标1:储存水量
            static int[][][] gridArray;  // 方格二维数组:M行 * N列 * 方格属性
            static int maxHeight    = 0; // 方格高度最大值

    final   static int INVALID_VALUE = -1; // 无效值

    public static void main(String[] args) {
        preprocess();               // 预处理
        addWater();                 // 加满水
        while (removeWater()) { }   // 移除水(直到无法再移除任何方格的水时停止)
        postprocess();              // 后处理
    }

    private static void preprocess() { // 预处理
        System.out.println("请输入方格二维数组的行数:");
        do {
            try {
                M = (new Scanner(System.in)).nextInt();
            } catch(Exception e) {
                M = INVALID_VALUE;
            }
        } while(M == INVALID_VALUE);

        System.out.println("请输入方格二维数组的列数:");
        do {
            try {
                N = (new Scanner(System.in)).nextInt();
            } catch(Exception e) {
                N = INVALID_VALUE;
            }
        } while(N == INVALID_VALUE);

        // 方格二维数组初始化
        System.out.println("请输入方格二维数组的数值:");
        gridArray = new int[M][N][GRID_WATER + 1];
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                do {
                    try {
                        gridArray[m][n][GRID_HEIGHT] = (new Scanner(System.in)).nextInt();
                    } catch(Exception e) {
                        gridArray[m][n][GRID_HEIGHT] = INVALID_VALUE;
                    }
                } while(gridArray[m][n][GRID_HEIGHT] == INVALID_VALUE);
                gridArray[m][n][GRID_WATER]     = 0;
            }
        }

        printArray(GRID_HEIGHT);
    }

    private static void addWater() { // 加满水
        // 方格高度最大值设定
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                if (maxHeight < gridArray[m][n][GRID_HEIGHT]) {
                    maxHeight = gridArray[m][n][GRID_HEIGHT];
                }
            }
        }

        // 加满水
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                gridArray[m][n][GRID_WATER] = maxHeight - gridArray[m][n][GRID_HEIGHT];
            }
        }
        System.out.print("加满水后,");
        printArray(GRID_WATER);
    }

    private static boolean removeWater() { // 移除水
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                if (canRemoveWater(m, n)) { // 还能移除水
                    System.out.print("移除水后,");
                    printArray(GRID_WATER);
                    return true; // 继续尝试移除水
                }
            }
        }
        return false; // 直到无法再移除任何方格的水时停止
    }

    private static boolean canRemoveWater(final int m, final int n) { // 能否移除水
        boolean returnValue = false;

        if (gridArray[m][n][GRID_WATER] > 0) { // 有水才有可能移除
            if (m == 0 || m == M -1 || n == 0 || n == N -1) { // 边界上的水都可以移除
                gridArray[m][n][GRID_WATER] = 0;
                returnValue = true;
            } else { // 非边界上的,如果高于周围的水都可以移除
                if (gridArray[m  ][n  ][GRID_WATER] + gridArray[m  ][n  ][GRID_HEIGHT] >
                    gridArray[m-1][n  ][GRID_WATER] + gridArray[m-1][n  ][GRID_HEIGHT]) { // 上
                    gridArray[m  ][n  ][GRID_WATER] =
                    gridArray[m-1][n  ][GRID_WATER] + gridArray[m-1][n  ][GRID_HEIGHT]
                                                    - gridArray[m  ][n  ][GRID_HEIGHT];
                    if (gridArray[m  ][n  ][GRID_WATER] < 0) {
                        gridArray[m  ][n  ][GRID_WATER] = 0;
                    }
                    returnValue = true;
                }
                if (gridArray[m  ][n  ][GRID_WATER] + gridArray[m  ][n  ][GRID_HEIGHT] >
                    gridArray[m+1][n  ][GRID_WATER] + gridArray[m+1][n  ][GRID_HEIGHT]) { // 下
                    gridArray[m  ][n  ][GRID_WATER] =
                    gridArray[m+1][n  ][GRID_WATER] + gridArray[m+1][n  ][GRID_HEIGHT]
                                                    - gridArray[m  ][n  ][GRID_HEIGHT];
                    if (gridArray[m  ][n  ][GRID_WATER] < 0) {
                        gridArray[m  ][n  ][GRID_WATER] = 0;
                    }
                    returnValue = true;
                }
                if (gridArray[m  ][n  ][GRID_WATER] + gridArray[m  ][n  ][GRID_HEIGHT] >
                    gridArray[m  ][n-1][GRID_WATER] + gridArray[m  ][n-1][GRID_HEIGHT]) { // 左
                    gridArray[m  ][n  ][GRID_WATER] =
                    gridArray[m  ][n-1][GRID_WATER] + gridArray[m  ][n-1][GRID_HEIGHT]
                                                    - gridArray[m  ][n  ][GRID_HEIGHT];
                    if (gridArray[m  ][n  ][GRID_WATER] < 0) {
                        gridArray[m  ][n  ][GRID_WATER] = 0;
                    }
                    returnValue = true;
                }
                if (gridArray[m  ][n  ][GRID_WATER] + gridArray[m  ][n  ][GRID_HEIGHT] >
                    gridArray[m  ][n+1][GRID_WATER] + gridArray[m  ][n+1][GRID_HEIGHT]) { // 右
                    gridArray[m  ][n  ][GRID_WATER] =
                    gridArray[m  ][n+1][GRID_WATER] + gridArray[m  ][n+1][GRID_HEIGHT]
                                                    - gridArray[m  ][n  ][GRID_HEIGHT];
                    if (gridArray[m  ][n  ][GRID_WATER] < 0) {
                        gridArray[m  ][n  ][GRID_WATER] = 0;
                    }
                    returnValue = true;
                }
            }
        }

        return returnValue;
    }

    private static void postprocess() { // 后处理
        int totalWater = 0; // 合计储存水量
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                totalWater += gridArray[m][n][GRID_WATER];
            }
        }
        System.out.println("合计储存水量" + ":" + totalWater);
    }

    private static void printArray(final int gridIndex) { // 打印数组
        switch (gridIndex) {
        case GRID_HEIGHT:
            System.out.println("方格高度" + ":");
            break;
        case GRID_WATER:
            System.out.println("储存水量" + ":");
            break;
        default:
            break;
        }
        for (int m = 0; m < M; m++) {
            for (int n = 0; n < N; n++) {
                System.out.print(gridArray[m][n][gridIndex] + " ");
            }
            System.out.println();
        }
    }
}
实现原理的思路展示:
1)首先,设定好方格二维数组,这个大家想法应该一样

2-1)其次,找到方格中的“至高点”
2-2)按照“至高点”填充所有方格,使其充满最大水量

3)然后开始移除水
3-1)如果在最外层的边界上的话,不能储存水
3-2)然后开始遍历整个数组,如果有能移除的水就移除掉,并且重复步骤3)
直到所有的水都不能移除为止
3-3)水是否能移除,就看当前位置的水位是否比 上下左右的水位高即可

4)打印剩下的水的总和即可
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值