zoukankan      html  css  js  c++  java
  • [BZOJ4027/HEOI2015]兔子与樱花

    Description

      很久很久之前,森林里住着一群兔子。有一天,兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它看成一个有根树结构,其中0号节点是根节点。这个树的每个节点上都会有一些樱花,其中第i个节点有c_i朵樱花。樱花树的每一个节点都有最大的载重m,对于每一个节点i,它的儿子节点的个数和i节点上樱花个数之和不能超过m,即son(i) + c_i <= m,其中son(i)表示i的儿子的个数,如果i为叶子节点,则son(i) = 0。

      现在兔子们觉得樱花树上节点太多,希望去掉一些节点。当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除,那么就会继续向上连接,直到第一个没有被删除的节点为止。
      现在兔子们希望计算在不违背最大载重的情况下,最多能删除多少节点。注意根节点不能被删除,被删除的节点不被计入载重。

    Input

      第一行输入两个正整数,n和m分别表示节点个数和最大载重;

      第二行n个整数c_i,表示第i个节点上的樱花个数;
      接下来n行,每行第一个数k_i表示这个节点的儿子个数,接下来k_i个整数表示这个节点儿子的编号。

    Output

       一行一个整数,表示最多能删除多少节点。

    Sample Input

    10 4
    0 2 2 2 4 1 0 4 1 1
    3 6 2 3
    1 9
    1 8
    1 1
    0
    0
    2 7 4
    0
    1 5
    0

    Sample Output

    4

    HINT

    对于100%的数据,1 <= n <= 2000000, 1 <= m <= 100000, 0 <= c_i <= 1000

    数据保证初始时,每个节点樱花数与儿子节点个数之和大于0且不超过m。
     
     
    题解:
      树形动态规划+贪心。对于任意一个节点,它当前的权值为c[i]+son[i]。假设我们删除了它的某一个儿子节点j,则权值增加c[j]+son[j]-1。那么显然,我们在删除节点的时候,应该从权值最小的到最大的依次进行,直到当前节点的权值已经超过限重。
      其实这种思路应该是算不上动态规划的,最重要的还是贪心部分。全过程直接用DFS就可以完成。建议加读入优化,2*10^6的数据不是盖的。
     
    代码:
    ----------------------------------------------------------------------------------------------------

    #include <cstdio>
    #include <algorithm>
    #define MAXN 2000005
    using namespace std;

    struct Edge { int v, next; } edge[MAXN];

    int w[MAXN], son[MAXN], n, m, now, h[MAXN], v, f[MAXN], st[MAXN];

    int read()
    {
      int res = 0; char ch = getchar();
      while (ch < '0' && ch > '9') ch = getchar();
      while (ch >= '0' && ch <= '9') res = res * 10 + ch - '0', ch = getchar();
      return res;
    }

    int DFS(int o)
    {
      int cnt = 0;
      for (int x = h[o]; x; x = edge[x].next)
      {
        int v = edge[x].v;
        DFS(v), w[o]++, f[o] += f[v];
      }
      for (int x = h[o]; x; x = edge[x].next) st[++cnt] = w[edge[x].v];
      sort(st + 1, st + cnt + 1);
      for (int i = 1; i <= cnt; i++)
        if (w[o] + st[i] - 1 <= m) w[o] += st[i] - 1, f[o]++; else break;
      return f[o];
    }

    int main()
    {
      freopen("4027.in", "r", stdin);
      freopen("4027.out", "w", stdout);
      n = read(), m = read();
      for (int i = 0; i <= n - 1; i++) w[i] = read();
      for (int i = 0; i <= n - 1; i++)
      {
        son[i] = read();
        for (int j = 1; j <= son[i]; j++) v = read(), now++, edge[now] = (Edge) {v, h[i]}, h[i] = now;
      }
      printf("%d", DFS(0));
      return 0;
    }

    ----------------------------------------------------------------------------------------------------
  • 相关阅读:
    微信小程序 WePY 2 框架入门教程
    微信小程序 WePY 1.7.X 框架入门教程
    /deep/ 深度作用选择器作用及使用
    微信小程序 wx.getUserProfile 接口获取用户信息
    Wepy 微信小程序项目踩坑记
    计算机网络-第一章概述OSI参考模型
    如何安装pycocotools为文件?
    第三章 系统总线
    第二章 计算机的发展和展望
    第一章 计算机基础概论
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4869020.html
Copyright © 2011-2022 走看看