最小的必要团队
作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。
所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。可以用每个人的编号来表示团队中的成员
1. 状态压缩 + 动态规划(0-1背包)
依次遍历员工,以固定访问顺序
同时遍历所有技能组合状态下的最小组合,依据新员工,产生新的状态,并记录最优值
class Solution {
public:
vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
int n = req_skills.size();
map<string,int> m;
for(int i=0;i<n;i++)
m[req_skills[i]] = i;//记录对应下标
int len = people.size();
vector<int> person(len);
for(int i=0;i<people.size();i++){
for(int j=0;j<people[i].size();j++){//遍历每一项技能
int item = 1<<m[people[i][j]];//技能对应位置
person[i] = person[i]|item; //记录掌握的全部技能
}
}
vector<vector<int>> dp(1<<n);//记录对应技能状态人员组成
for(int i=0;i<len;i++){ //遍历所有候选人员,0-1背包
for(int prev = 0; prev < dp.size(); prev++){//遍历所有技能状态
if(prev>0&&dp[prev].empty()) continue; //该状态为暂时未空,无法往后推导
int combine = prev|person[i]; //进行技能组合
if(combine==prev) continue;//该技能状态已包含这些技能,剪枝
if(dp[combine].empty()||dp[prev].size()+1<dp[combine].size()){//下一个状态为空,或者下一个状态存在更有结果,进行递推
dp[combine] = dp[prev]; //由上个状态组合而成
dp[combine].push_back(i);//同时加上新的候选人员
}
}
}
return dp[(1<<n)-1];
}
};