zoukankan      html  css  js  c++  java
  • P1113 杂务 题解

    题目传送门

    一、拓扑排序完整代码(bfs)

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 10010;
    int n;      //必须完成的杂务的数目
    int x;      //工作序号
    int y;      //一些必须完成的准备工作
    int ans;    //最终结果
    int a[N]; //完成工作所需要的时间a[x]
    int f[N]; //这个结点的最长时间
    
    vector<int> edge[N]; //出边链表
    int ind[N]; //入度
    queue<int> q; //队列
    /**
    测试数据:
    7
    1 5 0
    2 2 1 0
    3 3 2 0
    4 6 1 0
    5 1 2 4 0
    6 8 2 4 0
    7 4 3 5 6 0
    
    答案:
    23
    */
    
    int main() {
        //需要完成的杂务的数目
        cin >> n;
        //创建DAG
        for (int i = 1; i <= n; i++) {
            cin >> x >> a[x];
            while (cin >> y) {
                if (!y) break;
                //y是前序结点
                edge[y].push_back(x);//y结点出发到达x结点的边,所以x结点的入度++
                ind[x]++;//维护入度
            }
        }
        //步骤一:初始化队列,将入度为 0 的节点放入队列。
        for (int i = 1; i <= n; i++) {
            if (ind[i] == 0) {//如果入度为0,则为DAG的入口
                q.push(i);//入队列
                f[i] = a[i];//初始值,动态规划的base case
            }
        };
        //拓扑排序
        while (!q.empty()) {
            int p = q.front();
            q.pop();
            //步骤二:取出队首,遍历其出边,删除出边,将能够到达的点入度减一,同时维护答案数组。
            for (int i = 0; i < edge[p].size(); i++) {
                int y = edge[p][i];
                ind[y]--;
                if (ind[y] == 0) q.push(y);  //步骤三:若在此时一个点的入度变为 0,那么将其加入队列。
                //看看能不能获取到更大的时长
                f[y] = max(f[y], f[p] + a[y]);
            }
        }
        //统计答案
        for (int i = 1; i <= n; i++) ans = max(ans, f[i]);
        //输出大吉
        printf("%d
    ", ans);
        return 0;
    }
    

    二、拓扑排序完整代码(dfs)

    dfs本质是递归,如果从每个点发出进行深度优先,可以理解为自顶向下求以每个结点为出发点的最长链。为防止重复计算,可以使用记忆化搜索的办法对结果进行保存,已经探索完成的结点,不必重复进行搜索。

    比如,从1号结点出发,1号有两个出边,分别到达2和4,那么,在求解1号结点的最长链过程中,肯定是计算完毕2和4的,(否则1也算不出来啊),那么2和4需要再次计算时,就没必要算了,把结果直接给上就行了。这里需要特别说明的是:P260的图18-12绘制的含义,与代码的不尽一致!最上面的那个结点,最终不是像书中一样填写的是1,而是填写的是20,可以跟踪一下代码就明白了,vis[1]=20!如果看完那张图,再看代码,就会糊涂,就是因为它们两个表达的意思是反着的。

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 10010;
    int n;      //必须完成的杂务的数目
    int x;      //工作序号
    int y;      //一些必须完成的准备工作
    int ans;    //最终结果
    int a[N]; //完成工作所需要的时间a[x]
    int f[N]; //这个结点的最长时间
    vector<int> edge[N]; //出边链表
    
    /**
    测试数据:
    7
    1 5 0
    2 2 1 0
    3 3 2 0
    4 6 1 0
    5 1 2 4 0
    6 8 2 4 0
    7 4 3 5 6 0
    
    答案:
    23
    */
    /**
     * 功能:计算x号任务的最短完成时间
     * @param x
     * @return
     */
     /**
      总结:
      1、创建DAG的通用办法
      2、注意谁是出发点,谁是终止点
      3、深度优先搜索的应用,万能的魔法函数
      4、记忆化搜索优化深度优先搜索
      5、计算的是每个结点出发的最长链(自顶向下)
      */
    int dfs(int x) {
        //记忆化搜索,防止重复计算
        if (f[x]) return f[x];
        //找到连接到这个结点的边的最长的一个
        for (int i = 0; i < edge[x].size(); i++)
            f[x] = max(f[x], dfs(edge[x][i]));
        //加上本号任务的时长
        f[x] += a[x];
        //返回最短时间
        return f[x];
    }
    
    int main() {
        //创建DAG的标准套路
        //需要完成的杂务的数目
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> x >> a[x]; //完成工作所需要的时间len[x],注意:此处书中写的是len[i],也是可以AC的,
            // 原因是默认输入就是1,2,3...这样的输入,没有乱序输入。其实,如果没有乱序输入,
            // 这个cin>>x就是无用的,因为x肯定是等于i的。
            while (cin >> y) {
                //需要完成的准备工作
                if (!y) break;  //由一个数字0结束
                //前序啊!注意,这里是前序是谁!!!由谁到谁有一条有向边!!!
                edge[y].push_back(x); //这里要注意!!!! 是y向x有一条有向边,描述的是y是x的前序工作 !!!!
            }
        }
        //以上代码建图完毕!!!!
    
        //对于每项任务,分别计算最长工作时长,取最大值,就是最后的答案
        for (int i = 1; i <= n; i++) ans = max(ans, dfs(i));
        //输出大吉
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    4、10种数组去重的方法
    3.实现一个函数clone 可以对Javascript中的五种主要数据类型(Number、string、Object、Array、Boolean)进行复制
    2.怎么添加、移除、复制、创建、和查找节点
    1.简述同步和异步的区别
    89. 一行或多行文本超出隐藏
    88.阐述一下CSS Sprites(雪碧图)
    87、CSS属性overflow属性定义溢出元素内容区的内容会如何处理
    86.style标签写在body后与body前有什么区别?
    正则表达式:获取运算符之间变量
    反射问题(欢迎交流)
  • 原文地址:https://www.cnblogs.com/littlehb/p/15122085.html
Copyright © 2011-2022 走看看