20181010模拟赛 赛后处刑

版权声明: https://blog.csdn.net/qq_40828060/article/details/82999255

黄题第五套

Blossom

【问题描述】
ufo 在楼下的花园里种了棵树,这棵树上有 k 朵花。他还在树上的某节点
上藏了封密信。
有n只 lzl从密信的位置出发,经过不超过 d 段树枝,可
以到达的范围内包含所有的花。
可以到达的范围:如果从 a 出发,经过不超过 d 段树枝,可以到达 b,则 b
属于到达的范围,否则不属于。
【输入格式】
第一行 3 个整数 n,k,d,n 表示树的节点数,k,d 如题所示
第二行 k 个整数,表示有花的节点
后面 n-1 行每行两个整数,描述每段树枝连接的节点
【输出格式】
输出一行,一个整数,表示可能放密信的节点数
【样例输入】
6 2 3
1 2
1 5
2 3
3 4
4 5
5 6
【样例输出】
3
这道题第一眼树形dp,事实上也确实能做,然而不会
以下为十分亲民的Bfs做法
两遍bfs求距离最远的两朵花
两遍bfs以这两朵花作为起点扩展
脑补证明一下:
如果一朵花比这两朵花深度还大,那么所求的两朵花一定不是最优解
所以其他花的深度一定小于最优解
因此一个点只要能同时到达最优的两朵花,就一定能到达所有花

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
int const maxn=5001000;
int ans,n,k,d;
int cnt;
int head[maxn];
int dis[maxn],vis[maxn],isf[maxn],is[maxn],ind[maxn];
struct node
{
	int dis,id;
}maxx,fmaxx;
struct edge
{
	int to,next;
	edge(int to=0,int next=0):
		to(to),next(next){}
}e[maxn<<1];
void add(int u,int v)
{
	e[++cnt]=(edge){v,head[u]};
	head[u]=cnt;
}
void Bfs_best(int root)
//求距离最大的两朵花可以参考树的直径的求法
//随便找一个非花非叶节点的点作为根
//第一遍bfs找到最长链(终点是花)
//以终点为起点再跑一遍bfs,一、二次的终点即解
{
	memset(vis,0,sizeof(vis));
	memset(dis,0,sizeof(dis));
	std::queue<int>q;
	q.push(root);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=true;
		if(is[u])
			if(dis[u]>maxx.dis)
				maxx.dis=dis[u],maxx.id=u;
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(vis[v])
				continue;
			dis[v]=dis[u]+1;
			q.push(v);
		}
	}
}
void Bfs_imp(int root)
{
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	std::queue<int>q;
	q.push(root);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=true;
		if(dis[u]>d)
			continue;
		if(isf[u])
			ans++;
		isf[u]=true;
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(vis[v])
				continue;
			dis[v]=dis[u]+1;
			q.push(v);
		}
	}
}
int main()
{
//	freopen("in.in","r",stdin);
	memset(head,-1,sizeof(head));
	int root;
	scanf("%d%d%d",&n,&k,&d);
	for(int x,i=1;i<=k;i++)
		scanf("%d",&x),is[x]=true;
	for(int x,y,i=1;i<n;i++)
		scanf("%d%d",&x,&y),add(x,y),add(y,x),ind[x]++,ind[y]++;
	for(int i=1;i<=n;i++)
		if(ind[i]>1&&!is[i])
		{
			root=i;
			break;
		}
	Bfs_best(root);
	fmaxx.id=maxx.id;
	maxx.id=0,maxx.dis=0;
	Bfs_best(fmaxx.id);
	Bfs_imp(fmaxx.id);
	Bfs_imp(maxx.id);
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40828060/article/details/82999255