传送门
题目描述
最后,Bessie被迫去了一个远方的农场。这个农场包含N个谷仓(2 <= N <= 105)和N-1条连接两个谷仓的双向隧道,所以每两个谷仓之间都有唯一的路径。每个只与一条隧道相连的谷仓都是农场的出口。当早晨来临的时候,贝西将在某个谷仓露面,然后试图到达一个出口。
但当贝西露面的时候,她的位置就会暴露。一些农民在那时将从不同的出口谷仓出发尝试抓住贝西。农民和贝西的移动速度相同(在每个单位时间内,每个农民都可以从一个谷仓移动到相邻的一个谷仓,同时贝西也可以这么做)。农民们和贝西总是知道对方在哪里。如果在任意时刻,某个农民和贝西处于同一个谷仓或在穿过同一个隧道,农民就可以抓住贝茜。反过来,如果贝茜在农民们抓住她之前到达一个出口谷仓,贝西就可以逃走。
贝西不确定她成功的机会,这取决于被雇佣的农民的数量。给定贝西露面的谷仓K,帮助贝西确定为了抓住她所需要的农民的最小数量。假定农民们会自己选择最佳的方案来安排他们出发的出口谷仓。
输入格式
输入的第一行包含N和K.接下来的N - 1行,每行有两个整数(在1〜N范围内)描述连接两个谷仓的一条隧道。
输出格式
输出为了确保抓住贝茜所需的农民的最小数量。
由@Marser提供翻译
题目描述
最后走投无路,贝茜已经在一个偏远的农场里摔倒了。农场包括ñN个谷仓(2 \ leq N \ leq 10 ^ 52 ≤ Ñ ≤ 1 0
5
)和N-1在谷仓之间有 N - 1个双向隧道,因此每对谷仓之间都有一条独特的路径。每个只有一个隧道的谷仓就是一个出口。早上来的时候,贝茜将在一些谷仓露面并试图到达出口。
但贝西表面的那一刻,法律将能够确定她的位置。然后一些农民将从各个出口谷仓开始,并试图抓住贝茜。农民以与贝西相同的速度移动(因此在每个时间步骤中,每个农民可以从一个谷仓移动到相邻的谷仓)。农民知道贝茜在任何时候都在哪里,而贝茜在任何时候都知道农民在哪里。如果农民在任何时刻与Bessie在同一个谷仓,或者穿过与Bessie相同的隧道,农民就会抓住Bessie。相反,如果她在任何农场赶到她之前到达出口谷仓,贝茜就逃走了。
贝西不确定她取得成功的机会,这取决于法律能够部署的农民数量。鉴于Bessie在谷仓出现ķK,帮助Bessie确定捕获Bessie需要的最少农民数量,假设农民在出口谷仓中最佳地分配。
输入输出格式
输入格式:
输入的第一行包含 ñN和ķķ。以下各项N-1N - 1行指定两个整数,每个整数在范围内1 \ ldots N.1 … N,描述两个谷仓之间的隧道。
输出格式:
请输出确保捕获贝茜所需的最少农民数量。
输入输出样例
输入样例#1:
7 1
1 2
1 3
3 4
3 5
4 6
5 7
输出样例#1:
3
简化一下题意,就是给定一个迷宫,构成一棵有根树,你开始在根节点,出口是每个叶子节点,L可以在每个出口放一个守卫,每1个单位时间内,你和守卫都可以移动到相邻的一个点,如果某一时刻 守卫与你相遇了(在边上或点上均算),则你将被抓住。问为了保证抓住你,L最少需要几个守卫~~(以上文字是校内OJ的超级简化题面)~~ 。
我们先想一下,如果在每一个叶子结点都放一个农民,那么会怎样呢?
显然,不管奶牛怎么走,它一定会与某一个农民相遇。再想,放置农民的最佳方案一定是基于每一个农民都走最优路径的,而对于每一个农民,最优的方案一定是一直向上走。所以,当每个叶子结点都有农民时,奶牛一定会在某条路径的终点处与农民相遇。而现在假想,如果对于一个节点,如果它连且只连两个深度相同的叶节点,那么显然只需一个守卫;如果一个节点,它连且只连两个叶节点,那么只需要在深度小的叶节点放置就行了。
所以我们先遍历一遍全图,找出所有的叶节点,然后再深搜找出每一个节点的深度dep[i]与离它最近的叶节点之间的距离(深度差)mn[i],然后发现对于每一个节点,如果其深度大于等于该节点到最近叶节点的距离,说明现在就需要加个守卫,且以该节点为根的子树已经不需要其他的农民了(此时显然最佳方案是将农民放在那个最近的叶节点处),直接return就OK。
代码:
#include
#define INF 1e6
using namespace std;
inline int read(){
char ch;
int flag=1;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1;
int ans=ch-48;
while((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-48;
return ans*flag;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=100005;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0;
int mn[N],dep[N],pt[N];
int n,m;
int ans=0;
inline void add(int x,int y) {vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs(int v){
pt[v]=1;mn[v]=INF;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(pt[y]) continue;
dep[y]=dep[v]+1;
dfs(y);
mn[v]=min(mn[v],mn[y]+1);
}
if(mn[v]==INF) mn[v]=0;
}
int pt1[N];
void calc(int v){
pt1[v]=1;
if(mn[v]<=dep[v]) {++ans;return;}
for(int i=head[v];i;i=nxt[i]){
if(pt1[vis[i]]) continue;
calc(vis[i]);
}
}
int main(){
n=read(),m=read();
for(int x,y,i=1;i<n;i++){
x=read(),y=read();
add(x,y);add(y,x);
}
dfs(m);
calc(m);
write(ans);
return 0;
}