You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
5.2 KiB

2 years ago
package class43;
public class Code03_PavingTile {
/*
* 2*MN*M
*/
public static int ways1(int N, int M) {
if (N < 1 || M < 1 || ((N * M) & 1) != 0) {
return 0;
}
if (N == 1 || M == 1) {
return 1;
}
int[] pre = new int[M]; // pre代表-1行的状况
for (int i = 0; i < pre.length; i++) {
pre[i] = 1;
}
return process(pre, 0, N);
}
// pre 表示level-1行的状态
// level表示正在level行做决定
// N 表示一共有多少行 固定的
// level-2行及其之上所有行都摆满砖了
// level做决定让所有区域都满方法数返回
public static int process(int[] pre, int level, int N) {
if (level == N) { // base case
for (int i = 0; i < pre.length; i++) {
if (pre[i] == 0) {
return 0;
}
}
return 1;
}
// 没到终止行可以选择在当前的level行摆瓷砖
int[] op = getOp(pre);
return dfs(op, 0, level, N);
}
// op[i] == 0 可以考虑摆砖
// op[i] == 1 只能竖着向上
public static int dfs(int[] op, int col, int level, int N) {
// 在列上自由发挥玩深度优先遍历当col来到终止列i行的决定做完了
// 轮到i+1行做决定
if (col == op.length) {
return process(op, level + 1, N);
}
int ans = 0;
// col位置不横摆
ans += dfs(op, col + 1, level, N); // col位置上不摆横转
// col位置横摆, 向右
if (col + 1 < op.length && op[col] == 0 && op[col + 1] == 0) {
op[col] = 1;
op[col + 1] = 1;
ans += dfs(op, col + 2, level, N);
op[col] = 0;
op[col + 1] = 0;
}
return ans;
}
public static int[] getOp(int[] pre) {
int[] cur = new int[pre.length];
for (int i = 0; i < pre.length; i++) {
cur[i] = pre[i] ^ 1;
}
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 (col > 0 && (op & (3 << (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;
}
if (N == 1 || M == 1) {
return 1;
}
int big = N > M ? N : M;
int small = big == N ? M : N;
int sn = 1 << small;
int limit = sn - 1;
int[] dp = 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) {
int op = (~status) & limit;
dfs4(dp[status], op, 0, small - 1, cur);
}
}
for (int i = 0; i < sn; i++) {
dp[i] = 0;
}
int[] tmp = dp;
dp = cur;
cur = tmp;
}
return dp[limit];
}
public static void dfs4(int way, int op, int index, int end, int[] cur) {
if (index == end) {
cur[op] += way;
} else {
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 = 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));
}
}