Leetcode 5335. 参加考试的最大学生数 状压DP

OJ

每一行只与上一行有关,看成二进制,同时每一行最多2^8种状态,我们自然想到进行状态压缩

状态转移方程为:

dp[row][state] = max(dp[row-1][last] + state.count())

其中state代表某一个二进制数字,state.count代表当前数字的二进制有多少个1

注意我们需要检查合法性,这里包括:

本行的合法性:不能把学生安排在坏座位上;不能有相邻的学生
两行之间的合法性:如果第一行某个位置安排了学生,则下一行斜向的两个位置不能安排学生
最后的结果就是

max(dp[m][state])

代码

public int maxStudents(char[][] seats) {
    int o[] = new int[256], f[][] = new int[9][256], a[] = new int[9];
    int n = seats.length, m = seats[0].length, i, j, k, ans = 0;
    for (i = 1; i < 256; i++)
        // o用来记录某个数的二进制有多少个1
        o[i] = o[i >> 1] + (i & 1);
    for (int[] ints : f) {
        Arrays.fill(ints, Integer.MIN_VALUE);
    }
    for (i = 0; i < n; i++)
        for (j = 0; j < m; j++)
            if (seats[i][j] == '#')
                // a用二进制表示教室状态
                a[i] |= 1 << j;
    for (i = f[0][0] = 0; i < n; i++)
    	// 遍历一行的可能的坐人状态
        for (j = 0; j < 1 << m; j++)
        	// 验证是否有人坐在坏椅子上,验证是否有人坐在相邻位置
            if ((j & a[i]) == 0 && (j & j >> 1) == 0 && (j & j << 1) == 0)
                for (k = 0; k < 1 << m; k++)
                	// 与相邻行是否冲突
                    if ((j & k >> 1) == 0 && (j & k << 1) == 0)
                        f[i + 1][j] = Math.max(f[i + 1][j], f[i][k] + o[j]);
    for (i = 0; i < 1 << m; i++)
        ans = Math.max(ans, f[n][i]);
    return ans;
}
发布了180 篇原创文章 · 获赞 49 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/P19777/article/details/104233823