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