题目链接
给定一个教室图,“.”表示有一个座位,“#”表示没有座位
要求座位左前、右前、左边、右边四个方向座位均无人时才可坐下
求给定教室最多能坐几个人
状态压缩动态规划,因为每个座位是否可坐取决于当前排和前一排,因此对每排座位布局进行状态压缩
数据范围8 * 8,所以最多2 ^ 8 = 256种状态
状态转移方程:
dp[i][j] = max(dp[i][j], dp[i - 1][k] + CountBinary1(j))
其中i表示第几排
j、k表示该排座位状态压缩后的值
j、k布局应当满足题目要求
时间复杂度
O(N * (2 ^ (2 * M)))
Runtime: 0 ms beats 100%
Memory Usage: 2.2 MB
func maxStudents(seats [][]byte) (ans int) {
if len(seats) == 0 || len(seats[0]) == 0 {
return 0
}
m := len(seats)
n := len(seats[0])
dp := make([][]int, m)
for i := range dp { // 状态需要2 ^ len的长度
dp[i] = make([]int, int(math.Pow(2, float64(n))))
}
byteSeats := make([]int, m)
for i := range byteSeats {
for j := range seats[i] { // 按位压缩每一行的座椅位置
byteSeats[i] <<= 1
if seats[i][j] == '.' {
byteSeats[i] += 1
}
}
}
max := func(a, b int) int {
if a > b {
return a
}
return b
}
cnt1 := func(v int) (ans int) { // 计算一个int里二进制表示有多少个1
for ; v != 0; v >>= 1 {
if v & 1 == 1 {
ans++
}
}
return
}
for i := 0; i < m; i++ {
for j := 0; j < (1 << uint(n)); j++ {
if j | byteSeats[i] != byteSeats[i] || // 不是需要的座位组合
j & (j << 1) != 0 { // 邻座有人
continue
}
for k := 0; k < (1 << uint(n)); k++ {
if i == 0 {
dp[i][j] = cnt1(j)
break
}
if k | byteSeats[i - 1] != byteSeats[i - 1] ||
k & (k << 1) != 0 ||
((j << 1) & k) != 0 || // 两种情况分别是左前方右前方是否有人坐下
((j >> 1) & k) != 0 {
continue
}
dp[i][j] = max(dp[i][j], dp[i - 1][k] + cnt1(j))
}
}
}
for i := 0; i < (1 << uint(n)); i++ {
if dp[m- 1][i] > ans {
ans = dp[m- 1][i]
}
}
return
}