数据结构与算法--蛇行矩阵问题
题目描述
给定一个矩阵matrix,值有正、负、0
蛇可以空降到最左列的任何一个位置,初始增长值是0
蛇每一步可以选择右上、右、右下三个方向的任何一个前进
沿途的数字累加起来,作为增长值;但是蛇一旦增长值为负数,就会死去
蛇有一种能力,可以使用一次:把某个格子里的数变成相反数
蛇可以走到任何格子的时候停止
返回蛇能获得的最大增长值
import java.util.Arrays;public class Code04_SnakeGame {public static int maxValue(int[][] matrix){if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {return 0;}int ans = 0;for (int i = 0; i < matrix.length; i++) {for (int j = 0; j < matrix[0].length; j++) {Info res = f(matrix,i,j);ans = Math.max(ans, Math.max(res.no,res.yes));}}return ans;}public static class Info{int no;int yes;public Info(int no, int yes){this.no = no;this.yes = yes;}}public static Info f(int[][] matrix, int i, int j){if(j == 0){int no = Math.max(-1, matrix[i][0]);int yes = Math.max(-1, -matrix[i][0]);return new Info(no,yes);}//Info ans = new Info();int preNo = -1;int preYes = -1;Info preInfo = f(matrix,i,j-1);preNo = Math.max(-1, preInfo.no);preYes = Math.max(-1, preInfo.yes);if(i > 0){preInfo = f(matrix,i-1,j-1);preNo = Math.max(-1,Math.max(preNo, preInfo.no));preYes = Math.max(-1,Math.max(preYes, preInfo.yes));}if(i < matrix.length-1){preInfo = f(matrix,i+1,j-1);preNo = Math.max(-1,Math.max(preNo, preInfo.no));preYes = Math.max(-1,Math.max(preYes, preInfo.yes));}int no = preNo == -1 ? -1 : Math.max(-1, preNo + matrix[i][j]);int p1 = preYes == -1 ? -1 : Math.max(-1, preYes + matrix[i][j]);int p2 = preNo == -1 ? -1 : Math.max(-1, preNo - matrix[i][j]);int yes = Math.max(-1, Math.max(p1,p2));return new Info(no,yes);}// 从假想的最优左侧到达(i,j)的旅程中// 0) 在没有使用过能力的情况下,返回路径最大和,没有可能到达的话,返回负// 1) 在使用过能力的情况下,返回路径最大和,没有可能到达的话,返回负public static int[] process(int[][] m, int i, int j) {if (j == 0) { // (i,j)就是最左侧的位置return new int[] { m[i][j], -m[i][j] };}int[] preAns = process(m, i, j - 1);// 所有的路中,完全不使用能力的情况下,能够到达的最好长度是多大int preUnuse = preAns[0];// 所有的路中,使用过一次能力的情况下,能够到达的最好长度是多大int preUse = preAns[1];if (i - 1 >= 0) {preAns = process(m, i - 1, j - 1);preUnuse = Math.max(preUnuse, preAns[0]);preUse = Math.max(preUse, preAns[1]);}if (i + 1 < m.length) {preAns = process(m, i + 1, j - 1);preUnuse = Math.max(preUnuse, preAns[0]);preUse = Math.max(preUse, preAns[1]);}// preUnuse 之前旅程,没用过能力// preUse 之前旅程,已经使用过能力了int no = -1; // 之前没使用过能力,当前位置也不使用能力,的最优解int yes = -1; // 不管是之前使用能力,还是当前使用了能力,请保证能力只使用一次,最优解if (preUnuse >= 0) {no = m[i][j] + preUnuse;yes = -m[i][j] + preUnuse;}if (preUse >= 0) {yes = Math.max(yes, m[i][j] + preUse);}return new int[] { no, yes };}public static int walk2(int[][] matrix) {if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {return 0;}int max = Integer.MIN_VALUE;int[][][] dp = new int[matrix.length][matrix[0].length][2];for (int i = 0; i < dp.length; i++) {dp[i][0][0] = matrix[i][0];dp[i][0][1] = -matrix[i][0];max = Math.max(max, Math.max(dp[i][0][0], dp[i][0][1]));}for (int j = 1; j < matrix[0].length; j++) {for (int i = 0; i < matrix.length; i++) {int preUnuse = dp[i][j - 1][0];int preUse = dp[i][j - 1][1];if (i - 1 >= 0) {preUnuse = Math.max(preUnuse, dp[i - 1][j - 1][0]);preUse = Math.max(preUse, dp[i - 1][j - 1][1]);}if (i + 1 < matrix.length) {preUnuse = Math.max(preUnuse, dp[i + 1][j - 1][0]);preUse = Math.max(preUse, dp[i + 1][j - 1][1]);}dp[i][j][0] = -1;dp[i][j][1] = -1;if (preUnuse >= 0) {dp[i][j][0] = matrix[i][j] + preUnuse;dp[i][j][1] = -matrix[i][j] + preUnuse;}if (preUse >= 0) {dp[i][j][1] = Math.max(dp[i][j][1], matrix[i][j] + preUse);}max = Math.max(max, Math.max(dp[i][j][0], dp[i][j][1]));}}return max;}public static int[][] generateRandomArray(int row, int col, int value) {int[][] arr = new int[row][col];for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr[0].length; j++) {arr[i][j] = (int) (Math.random() * value) * (Math.random() > 0.5 ? -1 : 1);}}return arr;}public static void main(String[] args) {int N = 7;int M = 7;int V = 10;int times = 1000000;for (int i = 0; i < times; i++) {int r = (int) (Math.random() * (N + 1));int c = (int) (Math.random() * (M + 1));int[][] matrix = generateRandomArray(r, c, V);int ans1 = maxValue(matrix);int ans2 = walk2(matrix);if (ans1 != ans2) {for (int j = 0; j < matrix.length; j++) {System.out.println(Arrays.toString(matrix[j]));}System.out.println("Oops ans1: " + ans1 + " ans2:" + ans2);break;}}System.out.println("finish");}
}