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

原帖地址

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) {// 周边点比区域所有点都大的时候,区域内所有点可以+1
				for (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;
	}
}


猜你喜欢

转载自blog.csdn.net/lwb314/article/details/50969607
今日推荐