Dis2(distance2)

24 篇文章 0 订阅
3 篇文章 0 订阅

题目描述

给出一颗n个点n−1条边的树,点的编号为{1,2,…,n-1,n}1,2,…,n−1,n,对于每个点i(1<=i<=n),输出与点{i}i距离为{2}2的点的个数。
两个点的距离定义为两个点最短路径上的边的条数。

输入描述:

第一行一个正整数{n}n。
接下}n−1行每行两个正整数u,v
表示点u,v之间有一条边。

输出描述:

输出共n行,第i行输出一个整数表示与点i距离为2的点的个数。

样例

输入

4
1 2
2 3
3 4

输出

1
1
1
1

题目分析

其实这道题也不是很难,主要考察了大家的套娃(dp)能力,我看大佬说用树形dp,讲实话我觉得很有道理,题目一上来救赎树,这么大的数据量还没发用矩阵暴力乘出来(矩阵暴力乘:是指把边储存在临接矩阵里,矩阵的行数是爹,列数代表儿子,(爹,儿子)这个点为x代表有x条爹指向儿子的有向边,那么矩阵*矩阵得到的矩阵就是所谓的两步可达矩阵了),但是200000的数据量属实恐怖,那么就要另辟蹊径了。

尝试dp

我们在解决任何问题的时候,都要牢记我们解决的是什么,在这个问题里,我们要解决的是”任意一个点i,从他开始两步可达的点的个数”,这让我们马上想到了走楼梯问题,同样是方案数,同样是从另一个点走到另一个点。dp便忽然开朗了。
再重申一遍,我们要求的是“任意一个点i,从他开始两步可达的点的个数“,所以就考虑,任何一个点,怎么走两步到达其他点呢?结论很简单,简单到80岁老奶奶用假牙都能想出来,那就是走一步,再走一步,走两步就行了。所以dp什么也就很明显了,任何一点从他开始两步可达的点的个数=从他开始走一步可达的所有的点,再走一步可以到达点的个数 之和,就是我们要的答案。
(例如一个点x,其一步可达点为a b c,其中a连了3个点(包括x!!!),b连了2个点(包括x!!!),c连了1个点(包括x!!!),那么x的两步可达点的数量=3-1 + 2-1 + 1-1 =3)

AC代码

#include<iostream>
#include<vector>
using namespace std;
vector<int> vr[200100];
int main()
{
	int n;
	cin>>n;
	int u,v;
	while(scanf("%d%d",&u,&v)!=EOF)
	{
		vr[u].push_back(v);
		vr[v].push_back(u);
	}
	
	for(int i=1;i<=n;i++)
	{
		int temp;
		int ans=0;
		for(int j=0;j<vr[i].size();j++)
		{
			temp=vr[i][j];
			ans+=vr[temp].size()-1;
		}
		printf("%d\n",ans);
	}
	return 0}
				

接下来我们思考,Dis x

这个问题不难,也很好想到这个问题,如果要是题目中输入了要求x步可达的点的个数,怎么办?

如果x个,那么原函数就要套x层循环,所以就用优雅的暴力——函数递归

我之前写的博客里把他叫做搜索,但是自从用的越来越顺,我开始习惯叫递归,这是一种思想,而不是一种算法,是一种思路,而不是一种套路。当你把算法提炼为思路了,用起来自然会得心应手。

大家有兴趣自己写写吧,我现在这里凌晨1:43了,实在撑不住要去睡觉了,欢迎大家在评论区交流,对我的博客或者对算法竞赛有什么思路,意见都可以私信我,祝大家功力大涨!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值