动态规划-状态压缩-参加考试的最大学生数
2020-02-29 22:18:12
问题描述:


问题求解:
解法一:DFS
将原问题转化成图的问题,使用dfs去遍历得到解。
核心思想就是每次遍历到一个点,不仅将其标记为使用,还要将其周围的节点标记为访问过,避免之后遍历到矛盾的节点。
int res = 0;
public int maxStudents(char[][] seats) {
List<int[]> pos = new ArrayList<>();
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[0].length; j++) {
if (seats[i][j] == '.') pos.add(new int[]{i, j});
}
}
for (int[] start : pos) {
Set<int[]> used = new HashSet<>();
res = Math.max(res, dfs(pos, start, used));
}
return res;
}
private int dfs(List<int[]> pos, int[] start, Set<int[]> used) {
if (used.contains(start)) return 0;
used.add(start);
for (int[] next : pos) {
if (check(next, start) || check(start, next)) used.add(next);
}
int res = 1;
for (int[] next : pos) {
if (used.contains(next)) continue;
res += dfs(pos, next, used);
}
return res;
}
private boolean check(int[] p1, int[] p2) {
if (p1[0] == p2[0] && p1[1] == p2[1] - 1) return true;
if (p1[0] == p2[0] && p1[1] == p2[1] + 1) return true;
if (p1[0] == p2[0] - 1 && p1[1] == p2[1] - 1) return true;
if (p1[0] == p2[0] - 1 && p1[1] == p2[1] + 1) return true;
return false;
}
解法二:DP
本题最优的解法是DP,采取的思路是当前行的状态只和上一行相关,因此如果我们遍历上下行的所有状态,从中挑选出符合条件的状态,就可以得到解。
本题的思路和开关灯泡的搜索解有异曲同工的地方。
public int maxStudents(char[][] seats) {
int m = seats.length;
int n = seats[0].length;
int[] broken = new int[m + 1];
for (int i = 0; i < m; i++) {
int state = 0;
for (int j = 0; j < n; j++) {
if (seats[i][j] == '#') state |= (1 << j);
}
broken[i + 1] = state;
}
int[][] dp = new int[m + 1][1 << n];
for (int i = 1; i <= m; i++) {
for (int u = 0; u < (1 << n); u++) {
if ((u & (u >> 1)) != 0 || (u & broken[i - 1]) != 0) continue;
for (int v = 0; v < (1 << n); v++) {
if ((v & (v >> 1)) != 0 || (v & broken[i]) != 0 ||(v & (u >> 1)) != 0 || (v & (u << 1)) != 0) continue;
dp[i][v] = Math.max(dp[i][v], dp[i - 1][u] + helper(v));
}
}
}
int res = 0;
for (int i = 0; i < (1 << n); i++) res = Math.max(res, dp[m][i]);
return res;
}
private int helper(int num) {
int res = 0;
for (int i = 0; i < 32; i++) if ((num & (1 << i)) != 0) res += 1;
return res;
}
解法三:DP + 子集枚举
public int maxStudents(char[][] seats) {
int m = seats.length;
int n = seats[0].length;
int[] states = new int[m + 1];
for (int i = 0; i < m; i++) {
int state = 0;
for (int j = 0; j < n; j++) {
if (seats[i][j] == '.') state |= (1 << j);
}
states[i + 1] = state;
}
int[][] dp = new int[m + 1][1 << n];
for (int i = 1; i <= m; i++) {
for (int u = states[i - 1];; u = (u - 1) & states[i - 1]) {
for (int v = states[i];; v = (v - 1) & states[i]) {
if ((u & (u >> 1)) == 0 && (v & (v >> 1)) == 0 && (v & (u >> 1)) == 0 && (v & (u << 1)) == 0) dp[i][v] = Math.max(dp[i][v], dp[i - 1][u] + helper(v));
if (v == 0) break;
}
if (u == 0) break;
}
}
int res = 0;
for (int i = states[m];; i = (i - 1) & states[m]) {
res = Math.max(res, dp[m][i]);
if (i == 0) break;
}
return res;
}
private int helper(int num) {
int res = 0;
for (int i = 0; i < 32; i++) if ((num & (1 << i)) != 0) res += 1;
return res;
}

浙公网安备 33010602011771号