1125. 最小的必要团队

题面:

作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。

所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。

我们可以用每个人的编号来表示团队中的成员:例如,团队 team = [0, 1, 3] 表示掌握技能分别为 people[0],people[1],和 people[3] 的备选人员。

请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按任意顺序返回答案,本题保证答案存在。

示例 1:

输入:req_skills = ["java","nodejs","reactjs"], people = [["java"],["nodejs"],["nodejs","reactjs"]]
输出:[0,2]
示例 2:

输入:req_skills = ["algorithms","math","java","reactjs","csharp","aws"], people = [["algorithms","math","java"],["algorithms","math","reactjs"],["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
输出:[1,2]
 

提示:

1 <= req_skills.length <= 16
1 <= people.length <= 60
1 <= people[i].length, req_skills[i].length, people[i][j].length <= 16
req_skills 和 people[i] 中的元素分别各不相同
req_skills[i][j], people[i][j][k] 都由小写英文字母组成
本题保证「必要团队」一定存在

题解:

这题是一个01背包的变种,求最小值且要记录路径;

用二进制数来表示每个人掌握的技能。

f[j]表示满足j对应的所有技能最少的人数,初始时,f[0]=0,其余为正无穷;

与01背包一样,第一重循环枚举人,第二重循环从(1<<m)-1倒叙枚举到0,每次更新f[j|p[i]]=min(f[j|p[i]],f[j]+1),最后的个数f[(1<<m)-1];

每次转移的时候记录更新的过程,如果发生了min,记录g[j|p[i]]=make_pair(i,j),表示这个地方是从第i个人和状态j转移过去的,答案可以倒叙迭代,从j=(1<<m)-1到j==0,每次加入

g.first作为答案,然后j=g[j].second;

时间复杂度为n*2^m;空间复杂度0(n+2^m)

代码:

class Solution {
public:
    vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
        const int maxn=10000;
        unordered_map<string,int>skills;
        int m=0;
        for(auto s:req_skills)
            skills[s]=m++;
        int n=people.size();
        vector<int>p(n,0);
        for(int i=0;i<n;i++)
            for(auto s:people[i])
                p[i]=p[i]|(1<<skills[s]);
        vector<int>f(1<<m,maxn);
        vector<pair<int,int> >g(1<<m);
        f[0]=0;
        g[0]=make_pair(-1,-1);
        for(int i=0;i<n;i++)
            for(int j=(1<<m)-1;j>=0;j--)
                if(f[j|p[i]]>f[j]+1)
                {
                    f[j|p[i]]=f[j]+1;
                    g[j|p[i]]=make_pair(i,j);
                }
        vector<int>ans;
        for(int j=(1<<m)-1;j;j=g[j].second)
            ans.push_back(g[j].first);
        return ans;
    }
};

猜你喜欢

转载自www.cnblogs.com/flyljz/p/11672667.html