From 05dbccb9557553d79e3876d5f4a8b0f15591b6e0 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Thu, 25 Mar 2021 23:07:27 +0800 Subject: [PATCH] modify code --- src/class43/Code01_CanIWin.java | 54 +++++++++++- src/class43/Code02_TSP.java | 6 +- src/class43/Code03_PavingTile.java | 132 +++++++++++++++++++++++------ 3 files changed, 164 insertions(+), 28 deletions(-) diff --git a/src/class43/Code01_CanIWin.java b/src/class43/Code01_CanIWin.java index d271aa3..608b1f1 100644 --- a/src/class43/Code01_CanIWin.java +++ b/src/class43/Code01_CanIWin.java @@ -3,6 +3,49 @@ package class43; // leetcode 464题 public class Code01_CanIWin { + // 1~choose 拥有的数字 + // total 一开始的剩余 + // 返回先手会不会赢 + public static boolean canIWin0(int choose, int total) { + if (total == 0) { + return true; + } + if ((choose * (choose + 1) >> 1) < total) { + return false; + } + int[] arr = new int[choose]; + for (int i = 0; i < choose; i++) { + arr[i] = i + 1; + } + // arr[i] != -1 表示arr[i]这个数字还没被拿走 + // arr[i] == -1 表示arr[i]这个数字已经被拿走 + // 集合,arr,1~choose + return process(arr, total); + } + + // 当前轮到先手拿, + // 先手只能选择在arr中还存在的数字, + // 还剩rest这么值, + // 返回先手会不会赢 + public static boolean process(int[] arr, int rest) { + if (rest <= 0) { + return false; + } + // 先手去尝试所有的情况 + for (int i = 0; i < arr.length; i++) { + if (arr[i] != -1) { + int cur = arr[i]; + arr[i] = -1; + boolean next = process(arr, rest - cur); + arr[i] = cur; + if (!next) { + return true; + } + } + } + return false; + } + // 这个是暴力尝试,思路是正确的,超时而已 public static boolean canIWin1(int choose, int total) { if (total == 0) { @@ -14,12 +57,18 @@ public class Code01_CanIWin { return process1(choose, 0, total); } + // 当前轮到先手拿, + // 先手可以拿1~choose中的任何一个数字 + // status i位如果为0,代表没拿,当前可以拿 + // i位为1,代表已经拿过了,当前不能拿 + // 还剩rest这么值, + // 返回先手会不会赢 public static boolean process1(int choose, int status, int rest) { if (rest <= 0) { return false; } for (int i = 1; i <= choose; i++) { - if (((1 << i) & status) == 0) { + if (((1 << i) & status) == 0) { // i 这个数字,是此时先手的决定! if (!process1(choose, (status | (1 << i)), rest - i)) { return true; } @@ -37,6 +86,9 @@ public class Code01_CanIWin { return false; } int[] dp = new int[1 << (choose + 1)]; + // dp[status] == 1 true + // dp[status] == -1 false + // dp[status] == 0 process(status) 没算过!去算! return process2(choose, 0, total, dp); } diff --git a/src/class43/Code02_TSP.java b/src/class43/Code02_TSP.java index 2e4f670..bf984a6 100644 --- a/src/class43/Code02_TSP.java +++ b/src/class43/Code02_TSP.java @@ -31,11 +31,11 @@ public class Code02_TSP { if (cityNum == 1) { return matrix[start][0]; } - // 不只start这一座城 + // cityNum > 1 不只start这一座城 set.set(start, null); int min = Integer.MAX_VALUE; for (int i = 0; i < set.size(); i++) { - if (set.get(i) != null && i != start) { + if (set.get(i) != null) { // start -> i i... -> 0 int cur = matrix[start][i] + func1(matrix, set, i); min = Math.min(min, cur); @@ -68,7 +68,7 @@ public class Code02_TSP { int min = Integer.MAX_VALUE; // 枚举所有的城市 for (int move = 0; move < matrix.length; move++) { - if (move != start && (cityStatus & (1 << move)) != 0) { + if ((cityStatus & (1 << move)) != 0) { int cur = matrix[start][move] + f2(matrix, cityStatus, move); min = Math.min(min, cur); } diff --git a/src/class43/Code03_PavingTile.java b/src/class43/Code03_PavingTile.java index cd04ace..4a7ce01 100644 --- a/src/class43/Code03_PavingTile.java +++ b/src/class43/Code03_PavingTile.java @@ -22,9 +22,9 @@ public class Code03_PavingTile { // pre 表示level-1行的状态 // level表示,正在level行做决定 - // N 表示一共有多少行 固定的 + // N 表示一共有多少行 固定的 // level-2行及其之上所有行,都摆满砖了 - // level做决定,让所有区域都满,方法数返回s + // level做决定,让所有区域都满,方法数返回 public static int process(int[] pre, int level, int N) { if (level == N) { // base case for (int i = 0; i < pre.length; i++) { @@ -34,7 +34,7 @@ public class Code03_PavingTile { } return 1; } - + // 没到终止行,可以选择在当前的level行摆瓷砖 int[] op = getOp(pre); return dfs(op, 0, level, N); @@ -43,7 +43,7 @@ public class Code03_PavingTile { // op[i] == 0 可以考虑摆砖 // op[i] == 1 只能竖着向上 public static int dfs(int[] op, int col, int level, int N) { - // 在列上自由发挥,玩深度优先遍历,当col来到终止列,i行的决定做完了 + // 在列上自由发挥,玩深度优先遍历,当col来到终止列,i行的决定做完了 // 轮到i+1行,做决定 if (col == op.length) { return process(op, level + 1, N); @@ -51,7 +51,7 @@ public class Code03_PavingTile { int ans = 0; // col位置不横摆 ans += dfs(op, col + 1, level, N); // col位置上不摆横转 - // col位置横摆, 向右 + // col位置横摆, 向右 if (col + 1 < op.length && op[col] == 0 && op[col + 1] == 0) { op[col] = 1; op[col + 1] = 1; @@ -70,7 +70,92 @@ public class Code03_PavingTile { return cur; } + // Min (N,M) 不超过 32 public static int ways2(int N, int M) { + if (N < 1 || M < 1 || ((N * M) & 1) != 0) { + return 0; + } + if (N == 1 || M == 1) { + return 1; + } + int max = Math.max(N, M); + int min = Math.min(N, M); + int pre = (1 << min) - 1; + return process2(pre, 0, max, min); + } + + // 上一行的状态,是pre,limit是用来对齐的,固定参数不用管 + // 当前来到i行,一共N行,返回填满的方法数 + public static int process2(int pre, int i, int N, int M) { + if (i == N) { // base case + return pre == ((1 << M) - 1) ? 1 : 0; + } + int op = ((~pre) & ((1 << M) - 1)); + return dfs2(op, M - 1, i, N, M); + } + + public static int dfs2(int op, int col, int level, int N, int M) { + if (col == -1) { + return process2(op, level + 1, N, M); + } + int ans = 0; + ans += dfs2(op, col - 1, level, N, M); + if ((op & (1 << col)) == 0 && col - 1 >= 0 && (op & (1 << (col - 1))) == 0) { + ans += dfs2((op | (3 << (col - 1))), col - 2, level, N, M); + } + return ans; + } + + // 记忆化搜索的解 + // Min(N,M) 不超过 32 + public static int ways3(int N, int M) { + if (N < 1 || M < 1 || ((N * M) & 1) != 0) { + return 0; + } + if (N == 1 || M == 1) { + return 1; + } + int max = Math.max(N, M); + int min = Math.min(N, M); + int pre = (1 << min) - 1; + int[][] dp = new int[1 << min][max + 1]; + for (int i = 0; i < dp.length; i++) { + for (int j = 0; j < dp[0].length; j++) { + dp[i][j] = -1; + } + } + return process3(pre, 0, max, min, dp); + } + + public static int process3(int pre, int i, int N, int M, int[][] dp) { + if (dp[pre][i] != -1) { + return dp[pre][i]; + } + int ans = 0; + if (i == N) { + ans = pre == ((1 << M) - 1) ? 1 : 0; + } else { + int op = ((~pre) & ((1 << M) - 1)); + ans = dfs3(op, M - 1, i, N, M, dp); + } + dp[pre][i] = ans; + return ans; + } + + public static int dfs3(int op, int col, int level, int N, int M, int[][] dp) { + if (col == -1) { + return process3(op, level + 1, N, M, dp); + } + int ans = 0; + ans += dfs3(op, col - 1, level, N, M, dp); + if ((op & (1 << col)) == 0 && col - 1 >= 0 && (op & (1 << (col - 1))) == 0) { + ans += dfs3((op | (3 << (col - 1))), col - 2, level, N, M, dp); + } + return ans; + } + + // 严格位置依赖的动态规划解 + public static int ways4(int N, int M) { if (N < 1 || M < 1 || ((N * M) & 1) != 0) { return 0; } @@ -79,25 +164,16 @@ public class Code03_PavingTile { } int big = N > M ? N : M; int small = big == N ? M : N; - // big * small int sn = 1 << small; - int limit = sn - 1; // 全满状态 + int limit = sn - 1; int[] dp = new int[sn]; - dp[limit] = 1; // -1行全是满的 - // dp -1 行的状况 - // dp[0000] 0 - // dp[0001] 0 - // dp[1111] 1 - int[] cur = new int[sn]; // 当前行, 要算出所有状态下的解 + dp[limit] = 1; + int[] cur = new int[sn]; for (int level = 0; level < big; level++) { for (int status = 0; status < sn; status++) { - if (dp[status] != 0) { // 状态出现了 - // 0...1100 - // 1...0011 - // 0...1111 - // 0...0011 + if (dp[status] != 0) { int op = (~status) & limit; - dfs(dp[status], op, 0, small - 1, cur); + dfs4(dp[status], op, 0, small - 1, cur); } } for (int i = 0; i < sn; i++) { @@ -110,22 +186,30 @@ public class Code03_PavingTile { return dp[limit]; } - public static void dfs(int way, int op, int index, int end, int[] cur) { + public static void dfs4(int way, int op, int index, int end, int[] cur) { if (index == end) { cur[op] += way; } else { - dfs(way, op, index + 1, end, cur); - if (((3 << index) & op) == 0) { // 11 << index 可以放砖 - dfs(way, op | (3 << index), index + 1, end, cur); + dfs4(way, op, index + 1, end, cur); + if (((3 << index) & op) == 0) { // 11 << index 可以放砖 + dfs4(way, op | (3 << index), index + 1, end, cur); } } } public static void main(String[] args) { int N = 8; - int M = 8; + int M = 6; System.out.println(ways1(N, M)); System.out.println(ways2(N, M)); + System.out.println(ways3(N, M)); + System.out.println(ways4(N, M)); + + N = 10; + M = 10; + System.out.println("========="); + System.out.println(ways3(N, M)); + System.out.println(ways4(N, M)); } }