code
1. dfs暴力搜索
深搜所有状态,填X时要判断是否可行,没啥可说,暴力就完了,不过居然能过,规模确实小。
import java.util.Scanner;
//暴搜居然过
public class 矩阵计数_dfs暴搜 {
static int[][] map;
static int n;
static int m;
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
sc.close();
//long a=System.currentTimeMillis();
map = new int[n][m];
dfs(0,0);
System.out.println(ans);
//System.out.println(System.currentTimeMillis()-a);
}
static void dfs(int x, int y) {
if (x == n) {
ans++;
return;
}
if ((x < 2 || map[x - 1][y] == 0 || map[x - 2][y] == 0)
&& (y < 2 || map[x][y - 1] == 0 || map[x][y - 2] == 0)) {//判断是否可以为X
map[x][y] = 1;
if (y < m - 1)
dfs(x, y + 1);
else
dfs(x + 1, 0);
map[x][y] = 0;
}
if (y < m - 1)
dfs(x, y + 1);
else
dfs(x + 1, 0);
}
}
2. dfs+二进制枚举
用二进制来表示每一行的所有状态,省时省力。
不懂请搜:二进制枚举
import java.util.Scanner;
public class 矩阵计数_dfs_二进制枚举 {
static int[] map;
static boolean[] vis;
static int n;
static int m;
static int max;
static int ans;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
sc.close();
//long a = System.currentTimeMillis();
map = new int[n];
max = 1 << m;
vis = new boolean[max];
for (int i = 0; i < max; i++) {
vis[i] = check(i);
}
dfs(0);
System.out.println(ans);
//System.out.println(System.currentTimeMillis() - a);
}
static void dfs(int x) {
if (x == n) {
ans++;
return;
}
for (int i = 0; i < max; i++) {
if (!vis[i]&&(x < 2 || (map[x - 1] & map[x - 2] & i) == 0)) {
map[x] = i;
dfs(x + 1);
}
}
}
//判断是否有三个1连续
static boolean check(int x) {
int ans = 0;
while (x > 0) {
if ((x & 1) == 1)
ans++;
else
ans = 0;
if (ans == 3)
return true;
x >>= 1;
}
return false;
}
}
3. 状态压缩动态规划(状压dp)
同样用到了二进制
参考(python)
dp[i][j][k],表示第i行状态为j,上一行状态为k时,符合条件的方案数。
初始化:dp[0][i][0] = 1;j为每个符合条件的二进制状态。
转换方程:
for (int i = 1; i < n; i++)
for (int j : list)
for (int k :list)
for (int p : list)
if ((j & k & p) == 0)//判断有无连续三个1
dp[i][j][k] += dp[i - 1][k][p];
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class 矩阵计数_动态规划 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
sc.close();
//long a = System.currentTimeMillis();
List<Integer> list = new ArrayList<>();
int state=1<<m;
for (int i = 0; i < state; i++) {//筛选符合条件状态
if (!check(i))
list.add(i);
}
int[][][] dp = new int[n][state][state];
//初始化
for (int i : list)
dp[0][i][0] = 1;
for (int i = 1; i < n; i++)
for (int j : list)
for (int k :list)
for (int p : list)
if ((j & k & p) == 0)//判断有无连续三个1
dp[i][j][k] += dp[i - 1][k][p];
//统计
int ans = 0;
for (int i : list)
for (int j : list)
ans += dp[n - 1][i][j];
System.out.println(ans);
//System.out.println(System.currentTimeMillis() - a);
}
static boolean check(int x) {
int ans = 0;
while (x > 0) {
if ((x & 1) == 1)
ans++;
else
ans = 0;
if (ans == 3)
return true;
x >>= 1;
}
return false;
}
}
4. 三者对比
以6x6矩阵对比:
第三行为耗时,单位毫秒。
动态规划一骑绝尘,不过赛场上的话还是暴力直接过吧,时间有限。