1203. 项目管理

1203. 项目管理

公司共有 n 个项目和  m 个小组,每个项目要不无人接手,要不就由 m 个小组之一负责。

group[i] 表示第 i 个项目所属的小组,如果这个项目目前无人接手,那么 group[i] 就等于 -1。(项目和小组都是从零开始编号的)小组可能存在没有接手任何项目的情况。

请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:

同一小组的项目,排序后在列表中彼此相邻。
项目之间存在一定的依赖关系,我们用一个列表 beforeItems 来表示,其中 beforeItems[i] 表示在进行第 i 个项目前(位于第 i 个项目左侧)应该完成的所有项目。
如果存在多个解决方案,只需要返回其中任意一个即可。如果没有合适的解决方案,就请返回一个 空列表 。

 

示例 1:

输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3,6],[],[],[]]
输出:[6,3,4,1,5,2,0,7]


示例 2:

输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3],[],[4],[]]
输出:[]
解释:与示例 1 大致相同,但是在排序后的列表中,4 必须放在 6 的前面。
 

提示:

1 <= m <= n <= 3 * 104
group.length == beforeItems.length == n
-1 <= group[i] <= m - 1
0 <= beforeItems[i].length <= n - 1
0 <= beforeItems[i][j] <= n - 1
i != beforeItems[i][j]
beforeItems[i] 不含重复元素


基本思路:基于任务计划项目之间的明显的前后依赖关系,可以用拓扑排序解决问题。有两个核心点和3个注意点。

1.两个核心点:

  • 怎样进行拓扑排序:使用BFS从入度为零的点开始,将邻居逐步加入队列。具体上是将相邻点入度减去一,若入度为零,则加入队列中,循环进行,直至队列为空。
  • 怎么将同组的项目安排在一起:完成group2item的映射,然后根据组拓扑排序的顺序,将group转换成item。

2.三个注意点:

  • group[i]==-1,仅仅表示的是未安排,不是代表所有为-1的是同一组,需要预处理,防止误判
  • 组的邻接矩阵的获得,根据项目列表和beforeItems 获得组的依赖关系,如果当前项目于beforeitems[i]中的项目属于同一组,天然满足要求,直接pass
  • 在拓扑排序中,要注意环的问题,判断依据 ans.size()==n
    vector<int> topLogicalSort(vector<vector<int>> &adj,vector<int> &inDegree,int n){
        //dfs;

        queue<int> q;
        vector<int> ans;
        for(int i=0;i<inDegree.size();i++){
            if(inDegree[i]==0)
                q.push(i);
        }

        while(!q.empty()){
            int top=q.front();
            q.pop();
            ans.push_back(top);
            for(auto sub:adj[top]){
                inDegree[sub]--;
                if(inDegree[sub]==0){
                    q.push(sub);
                }
            }
        }
        if(ans.size()==n)
            return ans;
        return vector<int> ();
    }
    void print(vector<int> &aa){
        for(auto a:aa){
            cout<<a<<"  ";
        }
        cout<<endl;
    }
    vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
        //1.预处理,防止没有安排的项目组,被误认为同一个组
        for(int i=0;i<group.size();i++){
            if(group[i]==-1){
                group[i]=m;
                m++;
            }
        }

        //2.构建邻接表和统计入度。
        vector<vector<int>> itemAdj(n,vector<int>());
        vector<vector<int>> groupAdj(m,vector<int>());
        vector<int> itemIndegree(n,0);
        vector<int> groupIndegree(m,0);


        for(int i=0;i<n;i++){
            for(auto item:beforeItems[i]){
                itemAdj[item].push_back(i);
                itemIndegree[i]++;
            }
        }

        for(int i=0;i<n;i++){

            for(auto item:beforeItems[i]){
                if(group[item]==group[i])  //若是处于相同的组,那么肯定不会冲突
                    continue;
                groupAdj[group[item]].push_back(group[i]);
                groupIndegree[group[i]]++;
            }

        }
        //3.得到组和项目的拓扑排序
        vector<int> ans;
        auto groupList=topLogicalSort(groupAdj,groupIndegree,m);
        if(groupList.size()==0){
            return ans;
        }
        
        auto itemList=topLogicalSort(itemAdj,itemIndegree,n);
        if(itemList.size()==0){
            return ans;   //同时满足组和item的拓扑排序,那么必然有解
        }

        //4.用哈希表做组到项目的一对多的映射,直接将项目替换为项目,就是结果。
        unordered_map<int,vector<int>> group2item;
        for(auto item:itemList){
            group2item[group[item]].push_back(item);
        }
        for(auto gid:groupList){
            for(auto item:group2item[gid]){
                ans.push_back(item);
            }
        }

        return ans;


    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值