LeetCode:最小的必要團隊

題目描述:

作爲項目經理,你規劃了一份需求的技能清單 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]

思路:

這道題就是求母集合最少可以被多少個子集和組成。這種最優狀態通常可以用動態規劃來解決,但是難點在於你該如何表示團隊已有技能的狀態呢?看了網上的大神的題解,用二進制位來代表技能,0/1代表無/有對應的該項技能,那麼問題就開始明朗起來了,我們可以根據技能清單,利用map來對每個技能編0-(size-1)的號代表技能對應的位,子集i和對應的狀態have[i]就是裏面元素之或,然後定義一個dp數組用於動態規劃,dp[0]=0,狀態轉移方程if(dp[j|have[i]]>dp[j]+1) dp[j|have[i]]=dp[j]+1,如果某個狀態j在加上某個子集have[i]得到的狀態j|have[i]所需的最小子集dp[j|have[i]]大於原狀態所需最小子集dp[j]加一,那麼說明原狀態j加上這個子集have[i]得到的所需最小子集dp[j|have[i]]是更優的。我們在更新狀態的時候同時用一個數組記錄下最優子集的編號。

以下爲代碼:

class Solution {
public:
    vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
        unordered_map<string,int> skills;
        vector<int> dp(1<<req_skills.size(),-1);
        vector<pair<int,int>> record(1<<req_skills.size(),{-1,-1});
        vector<int> ans;
        for(int i=0;i<req_skills.size();i++)
            skills[req_skills[i]]=i;
        dp[0]=0;
        for(int i=0;i<people.size();i++)
        {
            int have=0;
            for(string skill:people[i])
                have|=1<<skills[skill];
            for(int j=0;j<dp.size();j++)
            {
                if(dp[j]==-1) continue;
                if((dp[j|have]>dp[j]+1)||(dp[j|have]==-1))
                {
                    dp[j|have]=dp[j]+1;
                    record[j|have].first=i;
                    record[j|have].second=j;
                }
            }
        }
        int ansb=(1<<req_skills.size())-1;
        while(ansb>0)
        {
            ans.push_back(record[ansb].first);
            ansb=record[ansb].second;
        }
        return ans;
    }
};

用位來代表是否擁有該技能,將其轉化爲一個動態規劃,這方法就是想不到,太久沒做題了,現在實在是太菜了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章