给你一个二维数组(比如是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)打印剩下的水的总和即可