【水笔】多年前看到的一道算法题,留念

来源:互联网 发布:介绍淘宝优惠券语句 编辑:程序博客网 时间:2024/05/16 18:34

原帖地址

http://bbs.csdn.net/topics/390712018


问题

新的题目又来了,这次还是有关矩阵的。

一个二维数组,向这样。把它想象成一个方格一个方格,数字代表了方格的高度。然后往这些方格里倒水。
当那么高度最低的肯定就可以存住水,问一个m*n的矩阵总共能存多少水。
拿这个矩阵举例子。能存水的肯定就是高度为0的2个点,而他们只能存单位为3的水。因为超过3就是边上的那个3冒出去了。
这个能理解吧。最短板的高度就是存水的高度。这次是只受上下左右4个方格的影响。所以这个矩阵能存水的数量是3+3=6.
9 9 9 9
3 0 0 9
7 8 9 6
再举个例子,这个矩阵能存水的数量就是1.因为只有2的上下左右是3,那么2这个点只能存1个单位的水。
11111
11311
13231
11311

算法就是给定任意m*n的矩阵,计算能存多少水。


代码实现




import java.util.ArrayList;import java.util.List;public class T3 {static int[][] array = { { 9, 9, 9, 9, 9, 10 }, { 9, 2, 2, 3, 11, 11 },{ 7, 2, 9, 12, 1, 20 }, { 7, 6, 3, 1, 11, 13 }, { 9, 9, 6, 9, 9, 14 } };static int height = array.length;static int width = array[0].length;// 数组宽static int sum = 0;// 总存储水的量public static void main(String[] a) throws Exception {int min = 10;int max = 10;int[][] array2 = new int[height][width];System.out.println("开始矩阵");for (int i = 0; i < array.length; i++) {for (int j = 0; j < array[i].length; j++) {array2[i][j]=array[i][j];System.out.print(array[i][j]);if (array[i][j] < 10) {System.out.print(" ,");} else {System.out.print(",");}}System.out.println();}for (int i = 1; i < array.length - 1; i++) {// 寻找最低点for (int j = 1; j < array[i].length - 1; j++) {if (array[i][j] < min) {min = array[i][j];}if (array[i][j] > max) {max = array[i][j];}}}for (int i = min; i < max; i++) {dosum(i);}System.out.println("结束矩阵");for (int i = 0; i < array.length; i++) {for (int j = 0; j < array[i].length; j++) {System.out.print(array[i][j]);if (array[i][j] < 10) {System.out.print(" ,");} else {System.out.print(",");}}System.out.println();}System.out.println("节点加水数情况");for (int i = 0; i < array.length; i++) {for (int j = 0; j < array[i].length; j++) {System.out.print(array[i][j]-array2[i][j]);if (array[i][j]-array2[i][j] < 10) {System.out.print(" ,");} else {System.out.print(",");}}System.out.println();}System.out.println("总共可以存水:" + sum);}//根据水位点找当前可以加水的点public static List<List<int[]>> getMin(int shuiwei) {List<List<int[]>> area = new ArrayList<List<int[]>>();// 区域for (int i = 1; i < array.length - 1; i++) {// 将最小的点加入到数组中作为起始计算的点for (int j = 1; j < array[i].length - 1; j++) {if (array[i][j] == shuiwei) {int[] point = { i, j };boolean flag = true;for (int k = 0; k < area.size(); k++) {List<int[]> pointList = area.get(k);if (contains(pointList, point)) {flag = false;break;}}if (flag) {List<int[]> pointList = new ArrayList<int[]>();pointList.add(point);found(shuiwei, pointList, pointList);area.add(pointList);}}}}return area;}//从一个点出发,查找周边的区域,且区域不包含最外层的点public static void found(int shuiwei, List<int[]> pointList,List<int[]> allPointList) {List<int[]> pointList2 = new ArrayList<int[]>();for (int i = 0; i < pointList.size(); i++) {int[] point = pointList.get(i);if(point[0]+1<height-1 && array[point[0]+1][point[1]]==shuiwei){int[] point2 = {point[0]+1,point[1]};if(!contains(allPointList, point2)){pointList2.add(point2);allPointList.add(point2);}}if(point[0]-1>0 && array[point[0]-1][point[1]]==shuiwei){int[] point2 = {point[0]-1,point[1]};if(!contains(allPointList, point2)){pointList2.add(point2);allPointList.add(point2);}}if(point[1]+1<width-1 && array[point[0]][point[1]+1]==shuiwei){int[] point2 = {point[0],point[1]+1};if(!contains(allPointList, point2)){pointList2.add(point2);allPointList.add(point2);}}if(point[1]-1>0 && array[point[0]][point[1]-1]==shuiwei){int[] point2 = {point[0],point[1]-1};if(!contains(allPointList, point2)){pointList2.add(point2);allPointList.add(point2);}}}if(pointList2.size()>0){found(shuiwei, pointList2, allPointList);}else{return;}}//做加水的运算public static void dosum(int shuiwei) {List<List<int[]>> list = getMin(shuiwei);List<List<int[]>> areaList = new ArrayList<List<int[]>>();// 保存新区域for (int i = 0; i < list.size(); i++) {// 循环区域List<int[]> pointList = new ArrayList<int[]>();// 保存新点List<int[]> roundList = new ArrayList<int[]>();// 周边的点for (int j = 0; j < list.get(i).size(); j++) {// 循环一个区域里的所有点。int[] point = list.get(i).get(j);// 最低点int[] pointTop = { point[0] - 1, point[1] };int[] pointLeft = { point[0], point[1] - 1 };int[] pointRight = { point[0], point[1] + 1 };int[] pointBottom = { point[0] + 1, point[1] };if (pointTop[0]>=0 && !contains(list.get(i), pointTop)) {// 将周边点加入,周边的点可以包括最外层的点roundList.add(pointTop);}if (pointLeft[1]>=0 && !contains(list.get(i), pointLeft)) {roundList.add(pointLeft);}if (pointRight[1]<width && !contains(list.get(i), pointRight)) {roundList.add(pointRight);}if (pointBottom[0]<height && !contains(list.get(i), pointBottom)) {roundList.add(pointBottom);}}boolean flag = true;// 看周边的点是不是比区域里的点小for (int j = 0; j < roundList.size(); j++) {int[] round = roundList.get(j);if (array[round[0]][round[1]] <= shuiwei) {flag = false;break;}}if (flag) {// 周边点比区域所有点都大的时候,区域内所有点可以+1for (int j = 0; j < list.get(i).size(); j++) {// 循环一个区域里的所有点。int[] point = list.get(i).get(j);// 区域内的点array[point[0]][point[1]] += 1;sum += 1;pointList.add(point);}if (pointList.size() > 0) {areaList.add(pointList);}}}}//判断数组是否包含点public static boolean contains(List<int[]> pointList, int[] point) {for (int i = 0; i < pointList.size(); i++) {if (pointList.get(i)[0] == point[0]&& pointList.get(i)[1] == point[1]) {return true;}}return false;}}


0 0
原创粉丝点击