黄题第五套
【问题描述】
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
#include
#include
#include
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::queueq;
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::queueq;
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;i1&&!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;
}