modify code

pull/6/head
algorithmzuo 5 years ago
parent 8367d441cb
commit 05dbccb955

@ -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]这个数字已经被拿走
// 集合arr1~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);
}

@ -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);
}

@ -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++) {
@ -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);
}
// 上一行的状态是prelimit是用来对齐的固定参数不用管
// 当前来到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));
}
}

Loading…
Cancel
Save