『树的贪心』51nod1314 定位系统

博客讲述了如何解决51nod1314题目的定位系统问题。通过分析树的性质,提出以节点为根的叶子节点加1的策略,并探讨了特殊情况下的反例,即链状结构中叶子节点的设定。总结了解题方法:枚举节点,考虑子树内是否存在链并据此调整答案。
摘要由CSDN通过智能技术生成

P r o b l e m \mathrm{Problem} Problem

在这里插入图片描述

S o l u t i o n \mathrm{Solution} Solution

这道题的题目大意是:

  • 你需要设定若干个点,使得任意两个点到设定的某一点距离不相同

这道题的推导比较复杂,我们需要挖掘这道题树的性质:

  • 在一个树上,如果我们强制设定某一个点,那么设定所有的叶子节点一定是合法的方案。
    在这里插入图片描述
    如图,例如3和4两种分成两叉的节点,我们可以根据距离叶子节点距离不同这一特点区分;例如2和1这种在某一分叉上面的节点,我们可以通过距离根节点和叶子结点不同这一特点来区分;因此,无论这棵树的形态怎么变,区分的方式只有这两种。
  • 根据以上性质,我们可以枚举每一个节点,答案为以该点为根的叶子结点 + 1 +1 +1.
  • 同时,这种做法也同样存在着反例。
    在这里插入图片描述
    如图所示,7号点的设定是完全没有必要的,因为该链只需要用到根的距离不同来区分即可。因此,我们发现出现链的情况下,叶子节点是不用设定的。
  • 但是,所有的链叶子节点都不用设定吗?
    在这里插入图片描述
    我们发现当链大于等于 2 2 2 条时,两条链的叶节点都不设定的话,便无法区分两条链,因此如果当前节点的子树如果链的条数大于等于1的话,我们便让答案 − 1 -1 1 即可.
  • 当然,这么做的前提是,仅在当前某点为根的子树内。因此在实际的操作上,我们统计子树全部完成了覆盖的方案,在根据是否存在一条完整的链来进行减一操作即可,该操作与子树是否完成了减一操作无关

C o d e \mathrm{Code} Code

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5;

int n, res(0), k;
int val[N];
vector < int > a[N];

int read(void)
{
	int s = 0, w = 0; char c = getchar();
	while (c < '0' || c > '9') w |= c == '-', c = getchar();
	while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();
	return w ? -s : s;
}

void Dfs2(int x,int fa,int Max,int sum)
{
	if (sum > Max) res += ((sum - Max) % k == 0);
	for (int i=0;i<a[x].size();++i)
	{
		int y = a[x][i];
		if (y == fa) continue;
		Dfs2(y,x,max(Max,val[y]),sum+val[y]);
	}
	return;
}

int main(void)
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n = read(), k = read();
	for (int i=1;i<n;++i)
	{
		int x = read(), y = read();
		a[x].push_back(y);
		a[y].push_back(x);	
	}	
	for (int i=1;i<=n;++i) val[i] = read();
	for (int i=1;i<=n;++i) 
		Dfs2(i,0,val[i],val[i]);
	cout << res / 2 + n << endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值