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

    题目描述

    很久很久之前,森林里住着一群兔子。有一天,兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由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

    现在兔子们觉得樱花树上节点太多,希望去掉一些节点。当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除,那么就会继续向上连接,直到第一个没有被删除的节点为止。

    现在兔子们希望计算在不违背最大载重的情况下,最多能删除多少节点。

    注意根节点不能被删除,被删除的节点不被计入载重。

    输入输出格式

    输入格式:

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

    第二行n个整数c_i,表示第i个节点上的樱花个数

    接下来n行,每行第一个数k_i表示这个节点的儿子个数,接下来k_i个整数表示这个节点儿子的编号

    输出格式:

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

    输入输出样例

    输入样例#1: 
    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
    输出样例#1: 
    4

    说明

    对于30%的数据,1 <= n <= 5000, 1 <= m <= 100, 0 <= c_i <= 100

    对于70%的数据,1 <= n <= 200000, 1 <= m <= 2000, 0 <= c_i <= 1000

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

    数据保证初始时,每个节点樱花数与儿子节点个数之和大于0且不超过m

    HEOI2015 T1。

    一上来的题应该不能太难吧,,,,,所以我直接往贪心上想了2333,幸好的确是个贪心题。

    我们考虑一个点删除带来的影响:(我们设一个节点的重量参数 h[i] = son[i] + c[i])

        一个点x被删除,仅会影响父节点的重量参数,且会让它的重量参数 +=c[x]+son[x]-1,也就是x的重量参数-1。

    所以我们可以先预处理出所有点的重量参数,因为上限都是m,所以就可以直接从下向上贪心了。

    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 2000005
    using namespace std;
    int to[maxn],ne[maxn];
    int hd[maxn],n,m,c[maxn];
    int siz[maxn],num=0,ans;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    void dfs(int x){	
    	int T=0,a[siz[x]+3];
    	siz[x]+=c[x];
    	for(int i=hd[x];i;i=ne[i]){
    		dfs(to[i]),a[++T]=siz[to[i]];
    	}
    	sort(a+1,a+T+1);
    	for(int i=1;i<=T;i++){
    		if(siz[x]+a[i]-1<=m){
    			siz[x]+=a[i]-1,ans++;
    		}
    		else return;
    	}
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;i++) c[i]=read();
    	int K,SON;
    	for(int i=0;i<n;i++){
    		siz[i]=K=read();
    		while(K--){
    			SON=read();
    			to[++num]=SON,ne[num]=hd[i],hd[i]=num;
    		}
    	}
    	
    	dfs(0);
    	
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8550444.html
Copyright © 2011-2022 走看看