zoukankan      html  css  js  c++  java
  • 动态规划-状态压缩-参加考试的最大学生数

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

      

      

  • 相关阅读:
    2018 ACM 网络选拔赛 徐州赛区
    2018 ACM 网络选拔赛 焦作赛区
    2018 ACM 网络选拔赛 沈阳赛区
    poj 2289 网络流 and 二分查找
    poj 2446 二分图最大匹配
    poj 1469 二分图最大匹配
    poj 3249 拓扑排序 and 动态规划
    poj 3687 拓扑排序
    poj 2585 拓扑排序
    poj 1094 拓扑排序
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12386649.html
Copyright © 2011-2022 走看看