最小的必要团队

作为项目经理,你规划了一份需求的技能清单 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];
    }
};

posted @ 2023-07-05 01:36  失控D大白兔  阅读(4)  评论(0编辑  收藏  举报