首页 > 其他分享 >【HEOI2015】兔子与樱花(贪心)

【HEOI2015】兔子与樱花(贪心)

时间:2022-10-28 20:46:59浏览次数:44  
标签:樱花 负载 删除 int HEOI2015 删去 节点 贪心

首先想一下题目中的操作如何转化:

当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。

设当前节点为 \(u\),\(u\) 的父节点为 \(fa\),儿子个数为 \(son_u\)。那么当我们把节点 \(u\) 删去时,\(fa\) 的樱花数会加上 \(c_u\),儿子个数会加上 \(son-1\)(减 \(1\) 是因为 \(u\) 本来是 \(fa\) 的儿子但被删去了)。

那么删去一个节点对其父亲的负载增加值就被我们算出来了,设为 \(val_i=c_u+son_u-1\)。

想了想 dp 做法没能想出来,于是想了一下贪心。

考虑从下往上贪心,设当前节点为 \(u\),先递归处理删除 \(u\) 的子树内除了 \(u\) 和 \(u\) 的儿子的节点(不妨把这些节点称为孙子节点,尽管它们可能是 u 的孙子、曾孙子、曾曾孙子)的最大贡献,再考虑删除 \(u\) 的儿子的最大贡献,然后回溯。

如何处理删除 \(u\) 的儿子对 \(u\) 的贡献?我们可以把 \(u\) 的儿子按它们的负载(孙子节点被删完后的负载),然后从小往大地删除,直到不能删为止(\(u\) 的负载要大于 \(m\) 时)。这样就能保证在有限的负载增加值中删去最多的节点。

为什么从下往上贪心是对的?

我们先画个图:

结合上面这个图,认为贪心不正确的人就会说:有没有可能我在 \(u=2\) 的时候删去了 \(3\) 号节点,增加了 \(2\) 节点的负载。导致在 \(u=1\) 的时候 \(2\) 节点因为负载过大而不能被删去。想一想,发现要删除 \(2\) 节点可能要取消删除 \(2\) 子树内的很多个节点,才能删除 \(2\) 节点,这样会使删除的节点数减少或不变,所以不如直接从下往上贪心。

代码如下:

#include<bits/stdc++.h>

#define N 2000010

using namespace std;

int n,m,ans,val[N],a[N];
int cnt,head[N],nxt[N],to[N];

void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

void dfs(int u)
{
	for(int i=head[u];i;i=nxt[i]) dfs(to[i]);//先递归
	int tot=0;
	for(int i=head[u];i;i=nxt[i]) a[++tot]=val[to[i]];//把每个子节点的负载值加入排序数组
	sort(a+1,a+tot+1);//排序
	for(int i=1;i<=tot;i++)
	{
		if(val[u]+a[i]-1<=m)//贪心取
		{
			val[u]+=a[i]-1;
			ans++;
		}
		else break;
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&val[i]);
	for(int i=1;i<=n;i++)
	{
		int k;
		scanf("%d",&k);
		val[i]=val[i]+k;//重新设置val
		for(int j=1;j<=k;j++)
		{
			int v;
			scanf("%d",&v);
			v++;//注意!
			adde(i,v);
		}
	}
	dfs(1);
	printf("%d\n",ans);
	return 0;
}

标签:樱花,负载,删除,int,HEOI2015,删去,节点,贪心
From: https://www.cnblogs.com/ez-lcw/p/16837423.html

相关文章

  • 【CQOI2017】小Q的棋盘(贪心)
    题意:给你一棵\(n\)个点的树,从根节点开始走\(m\)步,最多能遍历多少个节点。题解:考虑我们走的路径,设起点是\(S\),终点是\(T\),那么我们肯定是走的类似这么一条路径:设......
  • 最大子数组之和完成心得--贪心算法的应用
    intpre=0,maxAns=nums[0];for(intx:nums){pre=Math.max(pre+x,x);maxAns=Math.max(maxAns,pre);}......
  • 简单分解-最优分解贪心问题
    简单分解-最优分解贪心问题题目描述现有一个数,需要把n分解成一个或多个两两互不相同的正整数(例如:可以分解成,也可以分解成,但不能分解成。当然也可以不分解,这样能分解的结果......
  • 【PNR#2 Div1 D】找零(DP)(贪心)
    找零题目链接:PNR#2Div1D题目大意有500,100,50,10,5,1这些面额的纸币,你有X块钱,使用最少的纸币数表示的。然后有一些物品,每种只有一个,有费用。每次你可以选择一些......
  • 完全背包问题 —— 贪心优化 DP 范围
    题意:现在有\(2n+1\)个物品(\(n\le300\)),体积分别为\(-n,-n+1,\dots,-1,0,1,\dots,n\),第\(i\)个物品有\(a_i\)个,求选出恰好\(S\)的总体积最多能选几个物品。第一......
  • *PAT_甲级_1033 To Fill or Not to Fill (25分) (C++)【贪心算法】
    目录​​1,题目描述​​​​题目大意​​​​输入​​​​输出​​​​说明​​​​2,思路​​​​数据结构​​​​算法​​​​3,代码​​1,题目描述SampleInput1:5013001......
  • 2 道用到同个贪心 trick 的题目
    你别急,我可能不会。https://www.luogu.com.cn/problem/P4437https://www.luogu.com.cn/problem/UVA1205......
  • DFS(贪心问题)--解决最少数量装箱问题
    题目描述有重量分别为3,5,7公斤的三种货物,和一个载重量为X公斤的箱子(不考虑体积等其它因素,只计算重量)需要向箱子内装满X公斤的货物,要求使用的货物个数尽可能少(三种货物数量无......
  • 贪心找零钱
    题目描述楚乔、宇文玥和燕洵在日本旅行,经过了几天的游玩之后,钱包里出现了大量硬币,楚乔决定用钱包里的硬币为宇文玥和燕洵在自动贩卖机买水。楚乔的钱包里有1元、5元、10元、......
  • 贪心--(货币找零)
    题目描述楚乔、宇文玥和燕洵在日本旅行,经过了几天的游玩之后,钱包里出现了大量硬币,楚乔决定用钱包里的硬币为宇文玥和燕洵在自动贩卖机买水。楚乔的钱包里有1元、5元、10元、......