洛谷题目链接
WOJ题目链接
题目
洛谷[USACO18JAN] P4186 Cow at Large G
WOJ#3562 atlarge
题目描述
最后,Bessie被迫去了一个远方的农场。这个农场包含N个谷仓(2 <= N <= 105)和N-1条连接两个谷仓的双向隧道,所以每两个谷仓之间都有唯一的路径。每个只与一条隧道相连的谷仓都是农场的出口。当早晨来临的时候,Bessie将在某个谷仓露面,然后试图到达一个出口。
但当Bessie露面的时候,她的位置就会暴露。一些农民在那时将从不同的出口谷仓出发尝试抓住Bessie。农民和Bessie的移动速度相同(在每个单位时间内,每个农民都可以从一个谷仓移动到相邻的一个谷仓,同时Bessie也可以这么做)。农民们和Bessie总是知道对方在哪里。如果在任意时刻,某个农民和Bessie处于同一个谷仓或在穿过同一个隧道,农民就可以抓住Bessie。反过来,如果Bessie在农民们抓住她之前到达一个出口谷仓,Bessie就可以逃走。
Bessie不确定她成功的机会,这取决于被雇佣的农民的数量。给定Bessie露面的谷仓K,帮助Bessie确定为了抓住她所需要的农民的最小数量。假定农民们会自己选择最佳的方案来安排他们出发的出口谷仓。
输入
输入的第一行包含N和K。接下来的N – 1行,每行有两个整数(在1~N范围内)描述连接两个谷仓的一条隧道。
输出
输出为了确保抓住Bessie所需的农民的最小数量。
样例
- 输入样例
7 1
1 2
1 3
3 4
3 5
4 6
5 7 - 输出样例
3
题意
给定一棵有根树。贝茜从根节点出发,出口是每个叶子节点,可以在每个出口放一个农民,每1个单位时间内,贝茜和农民都可以移动到相邻的一个点,如果某一时刻农民与贝茜相遇了(在边上或点上均算),则贝茜将被抓住。求为了保证抓住贝茜,最少需要几个农民。
思路
首先明确一点:每个农民,每次都移动到自己的父亲节点,显然是最优的。
然后考虑最坏的情况:这棵树只有两层(如下图)。
因为懒得画图所以就拿mermaid将就一下啦凑合着看吧。
此时为了满足条件,我们需要在每一个叶子节点,都放一个农民。
然后考虑优化:当节点
i
i
i到根节点的距离,大于它到以
i
i
i为根的叶子结点
j
j
j的距离时,以
i
i
i为根的子树,就只需要安放一个
j
j
j节点就够了(如下图)。
所以我们预处理出了 i i i的子树上距 i i i最近的叶子节点 j j j到 i i i的最短距离,存储在 l a s t [ i ] last[i] last[i]中,将节点 i i i的深度存储在 d e p [ i ] dep[i] dep[i]中。然后遍历,如果 l a s t [ i ] < = d e p [ i ] last[i]<=dep[i] last[i]<=dep[i],则 i i i的子树均可以用这一个守卫守住,否则要去下面用更多的守卫( a n s + + ans++ ans++)。算一下答案即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n,m,root,cnt=2,ans=0;
int first[maxn],dep[maxn],last[maxn],fa[maxn];
struct edge {int u,v,nxt;};
edge e[maxn<<1];
inline int read()
{
int x=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-') {f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline void add(int u,int v)
{
e[cnt].u=u;e[cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt++;
}
void dfs(int x)
{
int son=0;
for(int i=first[x];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[x]) continue;
son++;
fa[v]=x;dep[v]=dep[x]+1;
dfs(v);
last[x]=min(last[x],last[v]+1);
}
if(!son)last[x]=0;
}
void solve(int x)
{
if(last[x]<=dep[x]) {ans++;return;}
for(int i=first[x];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[x]) continue;
solve(v);
}
}
int main()
{
memset(last,0x3f,sizeof(last));
n=read(),root=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs(root);
solve(root);
cout<<ans;
return 0;
}