题目描述
给了一个学生数组和老师数组,数组长度都是m
每个数组元素ei又是个数组,有k个元素,某个数组其中学生和老师的对应元素一样的个数定义为兼容性评分
问怎么匹配老师和学生的数组,让兼容性评分最大?
f1-状态压缩+动态规格 |
基本分析
- 这种两个等长数组匹配的题目怎么考虑?因为可以换顺序,固定一个不动,另一个枚举状态
- 这个得分的转移好些吗?对某个学生i,老师j的兼容性直接预处理就行,不要想的太复杂(比如异或)
- 剩下咋处理?常规的枚举老师状态,枚举最后一个老师位置i,之前的状态就是mask-1<<i,转移时择大取f[masx]
代码
class Solution:
def maxCompatibilitySum(self, students: List[List[int]], mentors: List[List[int]]) -> int:
# 预处理11对应的得分
m = len(students)
n = len(students[0])
cnt = [[0]*m for _ in range(m)]
for i in range(m):
for j in range(m):
c = 0
for k in range(n):
if students[i][k] == mentors[j][k]:
c += 1
cnt[i][j] = c
nmask = 1<<m
f = [0] * nmask
for mask in range(nmask):
c = bin(mask).count('1')
for i in range(m):
if mask &(1<<i):
f[mask] = max(f[mask], f[mask-(1<<i)] + cnt[c-1][i])
return f[-1]
复杂度
时间:\(预处理得分的一一对应关系O(n \cdot m^2), 状态及转移O(m \cdot 2^m)\)
空间:\(存对应得分O(m^2), 存dp结果2^m\)
总结
这个转移关系很好想,在处理兼容性得分的时候,一定要有预处理的思路。最开始想着能不能用异或实现,但是001 和001这种情况的异或不好处理,不如直接枚举处理简单
然后是转移的思路:这个mask不管顺序,只管选没选,然后从选了的人里面枚举最后一个,那么之前的状态就有了,并且肯定是算过的,而且对应的累加关系也是有的,肯定是第c个学生和枚举的最后的老师。