leetcode 1203.项目管理(C/C++/java/python)

PS:算法并非原创,仅作个人学习记录使用,侵删

题目描述
在这里插入图片描述

算法分析
一开始看到这类项目时间安排的题目,我就想起来算法里面的贪心算法。但是仔细想想,贪心算法涉及到具体的时间,且项目之间没有依赖关系。而这里的项目之间存在明显的依赖关系,于是我又想起了拓扑排序,也就是将项目作为结点,依赖关系作为边,建立有向图,然后根据有向图得出拓扑排序的序列。如果图中出现环,则说明排序无解。

代码实现
【C】

/*
算法思想:拓扑排序
*/
int* topSort(int* returnSize, int* deg, int** graph, int* graphColSize, int* items, int itemsSize) {
//返回数组大小:returnSize,项目的承办组:deg,图的邻接矩阵:graph,图的每行大小:graphColSize,项目数组:items,项目数目:itemsSize
    *returnSize = 0;//返回数组大小一开始为0
    int Q[itemsSize];
    int left = 0, right = 0;
    for (int i = 0; i < itemsSize; i++) {//遍历项目
        if (deg[items[i]] == 0) {//如果项目无人接管。
            Q[right++] = items[i];
        }
    }
    int* res = malloc(sizeof(int) * itemsSize);
    while (left < right) {
        int u = Q[left++];
        res[(*returnSize)++] = u;
        for (int i = 0; i < graphColSize[u]; i++) {
            int v = graph[u][i];
            if (--deg[v] == 0) {
                Q[right++] = v;
            }
        }
    }
    if (*returnSize == itemsSize) {
        return res;
    }
    *returnSize = 0;
    return NULL;
}

int* sortItems(int n, int m, int* group, int groupSize, int** beforeItems, int beforeItemsSize, int* beforeItemsColSize, int* returnSize) {
    int* groupItem[n + m];
    int groupItemColSize[n + m];
    int groupItemColCapacity[n + m];
    for (int i = 0; i < n + m; i++) {
        groupItem[i] = malloc(sizeof(int));
        groupItemColSize[i] = 0;
        groupItemColCapacity[i] = 0;
    }

    // 组间和组内依赖图
    int* groupGraph[n + m];
    int groupGraphColSize[n + m];
    int groupGraphColCapacity[n + m];
    for (int i = 0; i < n + m; i++) {
        groupGraph[i] = malloc(sizeof(int));
        groupGraphColSize[i] = 0;
        groupGraphColCapacity[i] = 0;
    }
    int* itemGraph[n];
    int itemGraphColSize[n];
    int itemGraphColCapacity[n];
    for (int i = 0; i < n; i++) {
        itemGraph[i] = malloc(sizeof(int));
        itemGraphColSize[i] = 0;
        itemGraphColCapacity[i] = 0;
    }

    // 组间和组内入度数组
    int groupDegree[n + m];
    memset(groupDegree, 0, sizeof(groupDegree));
    int itemDegree[n];
    memset(itemDegree, 0, sizeof(itemDegree));

    int id[n + m];
    for (int i = 0; i < n + m; ++i) {
        id[i] = i;
    }

    int leftId = m;
    // 给未分配的 item 分配一个 groupId
    for (int i = 0; i < n; ++i) {
        if (group[i] == -1) {
            group[i] = leftId++;
        }
        if (groupItemColSize[group[i]] == groupItemColCapacity[group[i]]) {
            int* x = &groupItemColCapacity[group[i]];
            *x = (*x) ? (*x) * 2 : 1;
            groupItem[group[i]] = realloc(groupItem[group[i]], sizeof(int) * (*x));
        }
        groupItem[group[i]][groupItemColSize[group[i]]++] = i;
    }
    // 依赖关系建图
    for (int i = 0; i < n; ++i) {
        int curGroupId = group[i];
        for (int j = 0; j < beforeItemsColSize[i]; j++) {
            int item = beforeItems[i][j];
            int beforeGroupId = group[item];
            if (beforeGroupId == curGroupId) {
                itemDegree[i]++;
                if (itemGraphColSize[item] == itemGraphColCapacity[item]) {
                    int* x = &itemGraphColCapacity[item];
                    (*x) = (*x) ? (*x) * 2 : 1;
                    itemGraph[item] = realloc(itemGraph[item], sizeof(int) * (*x));
                }
                itemGraph[item][itemGraphColSize[item]++] = i;
            } else {
                groupDegree[curGroupId]++;
                if (groupGraphColSize[beforeGroupId] == groupGraphColCapacity[beforeGroupId]) {
                    int* x = &groupGraphColCapacity[beforeGroupId];
                    (*x) = (*x) ? (*x) * 2 : 1;
                    groupGraph[beforeGroupId] = realloc(groupGraph[beforeGroupId], sizeof(int) * (*x));
                }
                groupGraph[beforeGroupId][groupGraphColSize[beforeGroupId]++] = curGroupId;
            }
        }
    }

    // 组间拓扑关系排序
    int groupTopSortSize;
    int* groupTopSort = topSort(&groupTopSortSize, groupDegree, groupGraph, groupGraphColSize, id, n + m);
    if (groupTopSortSize == 0) {
        *returnSize = 0;
        return NULL;
    }
    int* ans = malloc(sizeof(int) * groupTopSortSize);
    *returnSize = 0;
    // 组内拓扑关系排序
    for (int i = 0; i < groupTopSortSize; i++) {
        int curGroupId = groupTopSort[i];
        int size = groupItemColSize[curGroupId];
        if (size == 0) {
            continue;
        }
        int resSize;
        int* res = topSort(&resSize, itemDegree, itemGraph, itemGraphColSize, groupItem[curGroupId], groupItemColSize[curGroupId]);
        if (resSize == 0) {
            *returnSize = 0;
            return NULL;
        }
        for (int j = 0; j < resSize; j++) {
            ans[(*returnSize)++] = res[j];
        }
    }
    return ans;
}

C语言参考网址
【C++】

/*
算法思想:拓扑排序
*/
class Solution {
public:
    vector<int> sortItems(int n, int m, vector<int>& group, vector<vector<int>>& beforeItems) {
        for(int i = 0; i < n; i++){//遍历项目
            if(group[i] == -1)
                group[i] = m++;//无人接管的分配一个虚拟团队号
        }
        vector<vector<int>> itemgraph(n);
        vector<vector<int>> groupgraph(m);
        vector<int> itemIndegree(n, 0);
        vector<int> groupIndegree(m, 0);
        for(int i = 0; i < n; i++){
            for(auto j : beforeItems[i]){
                itemgraph[j].push_back(i);//建图
                itemIndegree[i]++;//记录出入度
                if(group[i] != group[j]){ // 注意条件
                // 团队也建图,记录出入度
                    groupgraph[group[j]].push_back(group[i]);
                    groupIndegree[group[i]]++;
                }
            }
        }
        vector<vector<int>> g_items(m);
        // item 拓扑排序
        queue<int> q;
        for(int i = 0; i < n; i++)
            if(itemIndegree[i] == 0)
                q.push(i);
        int countItem = 0;
        while(!q.empty()){
            int i = q.front();
            q.pop();
            countItem++;
            g_items[group[i]].push_back(i);
            //每个item顺序存入自己的团队
            for(auto j : itemgraph[i]){
                if(--itemIndegree[j]==0)
                    q.push(j);
            }
        }
        if(countItem != n)
            return {};
        // 团队拓扑排序
        vector<int> g_order;
        for(int i = 0; i < m; i++)
            if(groupIndegree[i] == 0)
                q.push(i);
        int countgroup = 0;
        while(!q.empty()){
            int g = q.front();
            q.pop();
            countgroup++;
            g_order.push_back(g);
            for(auto j : groupgraph[g]){
                if(--groupIndegree[j]==0)
                    q.push(j);
            }
        }
        if(countgroup != m)
            return {};
        // 写入答案
        vector<int> ans(n);
        int idx = 0;
        for(auto g : g_order){
            for(auto i : g_items[g])
                ans[idx++] = i;
        }
        return ans;
    }
};

C++参考网址

【java】

class Solution {
    public int[] sortItems(int n, int m, int[] group, List<List<Integer>> beforeItems) {
        List<List<Integer>> groupItem = new ArrayList<List<Integer>>();
        for (int i = 0; i < n + m; ++i) {
            groupItem.add(new ArrayList<Integer>());
        }

        // 组间和组内依赖图
        List<List<Integer>> groupGraph = new ArrayList<List<Integer>>();
        for (int i = 0; i < n + m; ++i) {
            groupGraph.add(new ArrayList<Integer>());
        }
        List<List<Integer>> itemGraph = new ArrayList<List<Integer>>();
        for (int i = 0; i < n; ++i) {
            itemGraph.add(new ArrayList<Integer>());
        }

        // 组间和组内入度数组
        int[] groupDegree = new int[n + m];
        int[] itemDegree = new int[n];

        List<Integer> id = new ArrayList<Integer>();
        for (int i = 0; i < n + m; ++i) {
            id.add(i);
        }

        int leftId = m;
        // 给未分配的 item 分配一个 groupId
        for (int i = 0; i < n; ++i) {
            if (group[i] == -1) {
                group[i] = leftId;
                leftId += 1;
            }
            groupItem.get(group[i]).add(i);
        }
        // 依赖关系建图
        for (int i = 0; i < n; ++i) {
            int curGroupId = group[i];
            for (int item : beforeItems.get(i)) {
                int beforeGroupId = group[item];
                if (beforeGroupId == curGroupId) {
                    itemDegree[i] += 1;
                    itemGraph.get(item).add(i);
                } else {
                    groupDegree[curGroupId] += 1;
                    groupGraph.get(beforeGroupId).add(curGroupId);
                }
            }
        }

        // 组间拓扑关系排序
        List<Integer> groupTopSort = topSort(groupDegree, groupGraph, id);
        if (groupTopSort.size() == 0) {
            return new int[0];
        }
        int[] ans = new int[n];
        int index = 0;
        // 组内拓扑关系排序
        for (int curGroupId : groupTopSort) {
            int size = groupItem.get(curGroupId).size();
            if (size == 0) {
                continue;
            }
            List<Integer> res = topSort(itemDegree, itemGraph, groupItem.get(curGroupId));
            if (res.size() == 0) {
                return new int[0];
            }
            for (int item : res) {
                ans[index++] = item;
            }
        }
        return ans;
    }

    public List<Integer> topSort(int[] deg, List<List<Integer>> graph, List<Integer> items) {
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int item : items) {
            if (deg[item] == 0) {
                queue.offer(item);
            }
        }
        List<Integer> res = new ArrayList<Integer>();
        while (!queue.isEmpty()) {
            int u = queue.poll();
            res.add(u);
            for (int v : graph.get(u)) {
                if (--deg[v] == 0) {
                    queue.offer(v);
                }
            }
        }
        return res.size() == items.size() ? res : new ArrayList<Integer>();
    }
}

java参考网址
【python】

class Solution:
    def sortItems(self, n, m, group, beforeItems):
        # 构建组到任务的映射
        group2Items = collections.defaultdict(set)
        index = m
        for i in range(n):
            if group[i] == -1:
                group[i] = index
                group2Items[index] = set([i])
                index += 1
            else:
                group2Items[group[i]].add(i)

        # 构建组的拓扑图
        beforeGroupsDic, preGroupsDic = {}, {}
        for i in range(index):
            beforeGroupsDic[i] = set()
            preGroupsDic[i] = set()
        for i in range(n):
            for j in beforeItems[i]:
                beforeGroupsDic[group[i]].add(group[j])
                preGroupsDic[group[j]].add(group[i])

        # 去除组内部的节点 如果存在环,在任务级别判断
        for i in range(index):
            if i in beforeGroupsDic[i]:
                beforeGroupsDic[i].remove(i)
                preGroupsDic[i].remove(i)
        res = []
        while beforeGroupsDic:
            # 找出所有入度为0的小组
            groups = [key for key, values in beforeGroupsDic.items() if not beforeGroupsDic[key]]
            if not groups:
                return []
            # 处理小组的拓扑关系
            for g in groups:
                beforeGroupsDic.pop(g)
                for g1 in preGroupsDic[g]:
                    beforeGroupsDic[g1].remove(g)
                preGroupsDic.pop(g)
            # 对小组内部建立拓扑图
            for key in groups:
                its = list(group2Items[key])
                # 对这些点建立拓扑图
                beforeItemsDic, preItemsDic = {}, {}
                for i in its:
                    beforeItemsDic[i] = set()
                    preItemsDic[i] = set()
                for i in its:
                    for j in beforeItems[i]:
                        if group[i] == group[j]:
                            beforeItemsDic[i].add(j)
                            preItemsDic[j].add(i)
                while beforeItemsDic:
                    items = [k for k, v in beforeItemsDic.items() if not beforeItemsDic[k]]
                    if not items:
                        return []
                    res += items
                    # 处理项目的拓扑关系
                    for item in items:
                        beforeItemsDic.pop(item)
                        for item1 in preItemsDic[item]:
                            if item1 in beforeItemsDic:
                                beforeItemsDic[item1].remove(item)
                        preItemsDic.pop(item)
        return res

python参考网址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值