首页 > 其他分享 >1349. 参加考试的最大学生数

1349. 参加考试的最大学生数

时间:2022-10-21 12:00:44浏览次数:43  
标签:1349 参加考试 状态 二进制 学生 state seats chair dp

题目描述

给一个m*n的矩阵seats表示教室内座位的分布,如果是坏的用“#”表示不能坐人
同时为了避免作弊,学生左,右,左前,右前4个位置不能有人
求给定座位后,最多能坐多少个学生?
提示:

  • 1<=m<=8
  • 1<=n<=8
f1-动态规划+状态压缩

基本分析

  1. 每一行坐人的状态怎么表示?参考给的数据规模,用二进制来表示坐人的状态
  2. 怎么满足以上的限制条件?
    • 坏的不能坐人?对某一行,预处理座位,把“#”用1代替,“.”用0代替,转化为二进制表达chair,如果chair&当前学生状态state==0,表示不冲突
    • 左右不能有人? state & (state >>1)==0 , state &(state<<1)==0
    • 左前右前不能有人?拿去前排的状态last_state, 和上面类似
  3. 怎么根据题目给出的seats表达,预处理出需要的二进制状态表达chair?
    • 增加了第0排的状态,都是0
    • 后续每排,拿到这一排坏的位置的索引,利用运算把1放到对应的位置上,这里是用到了reduce(函数,列表)方式实现
  4. 怎么定义dp状态?定义dp[i][state]表示第i排状态是state时候,前i排能坐的最大人数
  5. 怎么初始化dp状态?增加了一个第0排,chair也增加了第0排,两个可以对上。真正遍历从i=1开始,到i=m结束
  6. 怎么转移状态?dp[i][state] = max(dp[i][state], dp[i-1][last_state]+bin(state).count('1'))
  7. 怎么拿到做后的结果?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])

复杂度

时间:\(遍历m排,每排需要2^n * 2^n, 最终为O(m*2^{2n})\)
空间:\(O(m*2^n)\)

总结

  1. 用二进制表示人占据座位的情况
  2. 同样用在预处理的时候用二进制表示座位的占用情况
  3. 对于以上限制条件,用二进制的运算实现
  4. 在dp的时候,对初始化dp和chair的时候,都预先留了一个空排,以便可以从上往上顺序完成
  5. 还可以自顶向下实现,见后续解题

标签:1349,参加考试,状态,二进制,学生,state,seats,chair,dp
From: https://www.cnblogs.com/zk-icewall/p/16812960.html

相关文章