• 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;
        }
    };
  • 相关阅读:
    揭开Future的神秘面纱——任务取消
    阻塞队列和生产者-消费者模式
    ExecutorService——<T> Future<T> submit(Callable<T> task)
    ExecutorService接口概要
    Executor简介
    使用显式的Lock对象取代synchronized关键字进行同步
    SingleThreadExecutor(单线程执行器)
    后台线程(daemon)
    加入一个线程
    计算机网络的一些英文缩写词
  • 原文地址:https://www.cnblogs.com/flyljz/p/11672667.html
Copyright © 2020-2023  润新知