拓扑排序 + 动态规划(每日一题:2050. 并行课程 III)

class Solution {
    public int minimumTime(int n, int[][] relations, int[] time) {
        //建图使用List,并统计每个节点的 前置节点
        List[] g = new ArrayList[n];//构建拓扑排序图   数据结构:List数组
        Arrays.setAll(g, e -> new ArrayList()); //每个节点可能对应着多个后继结点 List数组每个元素为List
        int deg[] = new int[n];//统计每个节点的 前置节点数量
        for(var r : relations){
            int x = r[0] - 1,y = r[1] - 1;//咱们的数组 List都是从0开始,所以-1 x表示当前节点,y表示后节点
            g[x].add(y);
            deg[y]++; 
        }
        //首先将没有先修课的课加入队列。计算到达x的最大值,然后再遍历x的所有后置节点,更新到达后置节点的最大值,如果y没有了先修课,将其加入到队列
        var q = new ArrayDeque(); //队列维护的是 没有前置点的节点
        for(int i = 0;i < n;i++){
            if(deg[i] == 0){//表示该节点没有先修课 就是起点
                q.add(i);
            }
        }
        int f[] = new int[n];//存储到达当前节点并完成的最大用时
        int ans = 0;//维护最大值
        while(!q.isEmpty()){
            int x = q.poll();//取出并将没有前置点的点抛出
            f[x] += time[x];//到达节点x 再加上完成此课程x花费的时间,就是当前节点x完成所需的最大时间
            ans = Math.max(ans,f[x]);
            for(var y : g[x]){ //遍历x的所有后置点 往后面开始搜索
                f[y] = Math.max(f[x],f[y]);//到达该节点可能不止从x到达 也可能从其他节点到达 就需要求得最大值 动态规划
                if(--deg[y] == 0){ //节点y已经没有前置点 那么就入队
                    q.add(y);
                }
            }
        }
        return ans;

    }
}

/*
这不就是拓扑排序吗。
咋建图? 最终结果也就是从任意一个起点到终点 求时间和最大值。
完全不会,直接看题解。
原来还要用到 动态规划思想 不断求得最大值

关键点:
1、建立拓扑排序图 用List数组g 确定每个节点的后继结点 ;普通数组deg确定每个节点的前置节点数量
2、建立队列 初始化:将没有前置节点的节点加入队列
3、取出队列中的节点x,求出到达该节点完成用时 并维护最大值ans,然后遍历该节点的后继结点y,求出到达该节点完成最大的用时,若该节点已无前置节点则加入队列。



 */

你可能感兴趣的:(算法笔记,动态规划,代理模式,算法)