1349. 参加考试的最大学生数
题目描述
给一个m*n的矩阵seats表示教室内座位的分布,如果是坏的用“#”表示不能坐人
同时为了避免作弊,学生左,右,左前,右前4个位置不能有人
求给定座位后,最多能坐多少个学生?
提示:
- 1<=m<=8
- 1<=n<=8
f1-动态规划+状态压缩 |
基本分析
- 每一行坐人的状态怎么表示?参考给的数据规模,用二进制来表示坐人的状态
- 怎么满足以上的限制条件?
- 坏的不能坐人?对某一行,预处理座位,把“#”用1代替,“.”用0代替,转化为二进制表达chair,如果chair&当前学生状态state==0,表示不冲突
- 左右不能有人? state & (state >>1)==0 , state &(state<<1)==0
- 左前右前不能有人?拿去前排的状态last_state, 和上面类似
- 怎么根据题目给出的seats表达,预处理出需要的二进制状态表达chair?
- 增加了第0排的状态,都是0
- 后续每排,拿到这一排坏的位置的索引,利用运算把1放到对应的位置上,这里是用到了reduce(函数,列表)方式实现
- 怎么定义dp状态?定义dp[i][state]表示第i排状态是state时候,前i排能坐的最大人数
- 怎么初始化dp状态?增加了一个第0排,chair也增加了第0排,两个可以对上。真正遍历从i=1开始,到i=m结束
- 怎么转移状态?dp[i][state] = max(dp[i][state], dp[i-1][last_state]+bin(state).count('1'))
- 怎么拿到做后的结果?max(dp[m])
代码
class Solution: def maxStudents(self, seats: List[List[str]]) -> int: m, n = len(seats), len(seats[0]) # 预处理坏座位 chair = [0] for i in range(m): tmp = reduce(lambda x, y:x| 1<<y, [0] + [j for j in range(n) if seats[i][j]=="#"]) chair.append(tmp) mask = 1<<n dp = [[0]*mask for _ in range(m+1)] for i in range(1, m+1): for state in range(mask): if state & chair[i] == 0 and state & (state>>1) ==0 and state & (state<<1) ==0: for last_state in range(mask): if state & (last_state>>1) ==0 and state & (last_state<<1)==0: dp[i][state] = max(dp[i][state], dp[i-1][last_state] + bin(state).count('1')) return max(dp[m])
复杂度
时间:
空间:
总结
- 用二进制表示人占据座位的情况
- 同样用在预处理的时候用二进制表示座位的占用情况
- 对于以上限制条件,用二进制的运算实现
- 在dp的时候,对初始化dp和chair的时候,都预先留了一个空排,以便可以从上往上顺序完成
- 还可以自顶向下实现,见后续解题
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现