zoukankan      html  css  js  c++  java
  • 洛谷 P2018 消息传递

    题目分析

    贪心+树形DP

    本来还以为要大费周折地换根,然后发现 (n) 很小,可以直接 (O(n^2log n)) 枚举。

    枚举每个节点作为根,用 (f_x) 表示走完以 (x) 为根的子树花费的最小时间。

    那么如何更新呢?这个时候就要用到贪心的思想了。假设我们现在已经知道了 (x) 的儿子个数 (tot) 以及所有儿子 (to)(f) 值。那么 (x) 必定要把信息传给每一个儿子,所以要尽量早地把信息传给 (f) 值较大的儿子,因此要把所有儿子的 (f) 值从小到大排序,并得出如下 DP 方程:

    [f_{x}=maxlimits_{i=1}^{tot}(f_{to}+i) ]

    最后的答案需要加 (1),因为最开始要花费 (1) 的时间把消息传播到根节点。

    计算出以每个点为根的答案之后取最小值,再扫描一遍找可以作为根的点即可。

    特别注意

    在更新当前节点时,需要记录所有儿子的 (f) 值,如果要定义临时数组只能在函数内定义,因为在接下来的 dfs 过程中又用到了此数组,数组中的值会因此发生改变,所以不能在外面定义。

    代码

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 1e3 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    struct node { int to, nxt; } e[A << 1];
    int n, ans[A], f[A], head[A], cnt = 0, res = inf; 
    
    inline void add(int from, int to) {
      e[++cnt].to = to;
      e[cnt].nxt = head[from];
      head[from] = cnt;
    }
    
    bool cmp(int x, int y) {
      return x > y;
    }
    
    inline void dfs(int x, int fa) {
      int tot = 0, b[1000] = {0};
      
      for (int i = head[x]; i; i = e[i].nxt) {
        int to = e[i].to;
        if (to == fa) continue;
        dfs(to, x);
        b[++tot] = f[to];
      }
      sort(b + 1, b + 1 + tot, cmp);
      for (int i = 1; i <= tot; i++) 
        f[x] = max(f[x], b[i] + i);
    }
    
    int main() {
      n = read();
      for (int i = 2; i <= n; i++) {
        int x = read();
        add(x, i), add(i, x);
      }
      for (int i = 1; i <= n; i++) {
        memset(f, 0, sizeof(f));
        dfs(i, 0);
        res = min(f[i], res);
        ans[i] = f[i];
      }
      cout << res + 1 << '
    ';
      for (int i = 1; i <= n; i++) 
        if (ans[i] == res) cout << i << " ";
      puts("");
      return 0;
    }
    
  • 相关阅读:
    团队作业第三次——项目需求分析
    快乐就队——第八次站立式会议(05-02)
    快乐就队——第七次站立式会议(04-30)
    快乐就队——第六次站立式会议(04-29)
    快乐就队——第五次站立式会议(04-28)
    快乐就队——第四次站立式会议(04-27)
    快乐就队——第三次站立式会议(04-26)
    快乐就队——第二次站立式会议(04-25)
    快乐就队——第一次站立式会议(04-24)
    快乐就队——项目系统设计与数据库设计
  • 原文地址:https://www.cnblogs.com/loceaner/p/13986385.html
Copyright © 2011-2022 走看看