给你一个 m * n 的矩阵 seats 表示教室中的座位分布。如果座位是坏的(不可用),就用 '#' 表示;否则,用 '.' 表示。
学生可以看到左侧、右侧、左上、右上这四个方向上紧邻他的学生的答卷,但是看不到直接坐在他前面或者后面的学生的答卷。请你计算并返回该考场可以容纳的一起参加考试且无法作弊的最大学生人数。
学生必须坐在状况良好的座位上。
示例 1:
输入:seats = [["#",".","#","#",".","#"],
[".","#","#","#","#","."],
["#",".","#","#",".","#"]]
输出:4
解释:教师可以让 4 个学生坐在可用的座位上,这样他们就无法在考试中作弊。
示例 2:
输入:seats = [[".","#"],
["#","#"],
["#","."],
["#","#"],
[".","#"]]
输出:3
解释:让所有学生坐在可用的座位上。
示例 3:
输入:seats = [["#",".",".",".","#"],
[".","#",".","#","."],
[".",".","#",".","."],
[".","#",".","#","."],
["#",".",".",".","#"]]
输出:10
解释:让学生坐在第 1、3 和 5 列的可用座位上。
提示:
seats 只包含字符 '.' 和'#'
m == seats.length
n == seats[i].length
1 <= m <= 8
1 <= n <= 8
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-students-taking-exam
解法:状态压缩dp。
这是写状压dp的第二题,状态都是用二进制表示的。dp[i][state],表示第i行状态为state时,最多学生数目。写位运算符的时候一定要注意优先级,&、|、^、都是小于==
class Solution {
public:
int maxStudents(vector<vector<char>>& seats) {
int m = seats.size(), n=seats[0].size();
vector<vector<int>>dp(m + 1, vector<int>(1 << n));
int pre = 0;
for (int i = 1; i <= m; ++i)
{
int S = 0;
for (int j = 0; j < n; ++j)
{
if (seats[i - 1][j] == '.')
S += (1 << j);
}
for (int mask = S; mask >= 0; mask = (mask - 1)&S) //在S的子状态中搜索,一般来讲mask应!=0,但本题需要
{
int tL = mask << 1, tR = mask >> 1;
if ((tL&mask) || (tR&mask))
continue;
int cnt = __builtin_popcount(mask);
for (int maskP = pre; maskP >= 0; maskP = (maskP - 1)&pre) //在i-1行中的子状态中搜索
{
if ((tL&maskP) || (tR&maskP))
continue;
dp[i][mask] = max(dp[i][mask], dp[i - 1][maskP] + cnt);
if(maskP==0)
break;
}
if(mask==0) //mask==0时break
break;
}
pre = S;
}
int ans = 0;
for (int mask = pre; mask >= 0; mask = (mask - 1)&pre)
{
ans = max(dp[m][mask], ans);
if(mask==0)
break;
}
return ans;
}
};
记忆化+状态压缩。可以根据dp解法进行更改。我们可以发现,第i行的安排情况只能影响到第i+1行的安排情况。dfs(seat, cur,m)表示第cur-1行状态为seat时,能安排最多的学生数。还需加个记忆化。
class Solution {
int getBin(const vector<char> &seat, const int &n)
{
int ans = 0;
for (int i = 0; i < n; ++i)
{
if (seat[i] == '.')
ans |= (1 << i);
}
return ans;
}
vector<int> row_seats;
vector<vector<int>> memo;
int dfs(int seat, int cur, const int &m)
{
if (cur == m)
return 0;
if(memo[cur][seat]!=-1)
return memo[cur][seat];
int mask = row_seats[cur];
int ans = 0;
for (int sub = mask; sub >= 0; sub = (sub - 1)&mask)
{
if ((seat << 1)&sub || (seat >> 1)&sub||(sub>>1)&sub||(sub<<1)&sub)
continue;
ans = max(ans, dfs(sub, cur + 1, m)+__builtin_popcount(sub));
if (sub == 0)
break;
}
memo[cur][seat]=ans;
return ans;
}
public:
int maxStudents(vector<vector<char>>& seats) {
int m = seats.size(), n = seats[0].size();
memo.resize(m, vector<int>(1<<n, -1));
for (int i = 0; i < m; ++i)
row_seats.push_back(getBin(seats[i], n));
return dfs(0, 0, m);
}
};