[USACO18JAN] Cow at Large G (dfs)

题目大意:有一只狐狸从给定的S点开始逃跑(出发),向叶节点移动以逃离这棵树,叶节点可能出现农民去抓捕狐狸,当农民和狐狸出现在同一个节点的时候,狐狸会被抓住,农民和狐狸移动速度相同,求抓捕狐狸所需要的最少农民数

显然,当 u 节点的子树内存在一叶节点 i 满足deep[i]-deep[u]<=deep[u]时,说明 u 的子树能被守住

即农民从 i 移动到 u 所需要的时间小于等于狐狸从出发点移动到 u 的时间

第一遍dfs预处理出每个节点的深度dep,以及每个节点的子树内深度最小的叶节点的深度mindep(代码中简化为mi)

第二遍dfs求答案,只要某个节点能被其子树内某个叶节点守住,那么它子树内其它节点就不用考虑了,return 1

但并不能从S点直接开始第二个dfs,而是从S点直接连接的所有节点开始,因为狐狸和农民移动速度一样,如果按之前的方法,狐狸可能会往相反方向跑,导致农民无法追上狐狸

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 100005
 5 #define inf 0x3f3f3f3f
 6 #define maxn 1000010
 7 using namespace std;
 8 //re
 9 
10 int n,S,cte;
11 int head[N],dep[N],mi[N],inc[N];
12 struct Edge{int to,nxt;}edge[N*2];
13 void ae(int u,int v){
14     cte++;edge[cte].to=v,inc[v]++;
15     edge[cte].nxt=head[u],head[u]=cte;
16 }
17 void dfs1(int u,int fa)
18 {
19     if(inc[u]==1) {mi[u]=dep[u];return;}
20     for(int j=head[u];j;j=edge[j].nxt){
21         int v=edge[j].to;
22         if(v==fa) continue;
23         dep[v]=dep[u]+1;
24         dfs1(v,u);
25         mi[u]=min(mi[u],mi[v]);
26     }
27 }
28 int dfs2(int u,int fa)
29 {
30     int ans=0;
31     if(mi[u]-dep[u]<=dep[u])
32         return 1;
33     for(int j=head[u];j;j=edge[j].nxt){
34         int v=edge[j].to;
35         if(v==fa) continue;
36         ans+=dfs2(v,u);
37     }
38     return ans;
39 }
40 
41 int main()
42 {
43     scanf("%d%d",&n,&S);
44     int x,y,ans=0;
45     for(int i=1;i<n;i++)
46         scanf("%d%d",&x,&y),ae(x,y),ae(y,x);
47     memset(mi,0x3f,sizeof(mi));
48     dfs1(S,-1);
49     for(int j=head[S];j;j=edge[j].nxt){
50         int v=edge[j].to;
51         ans+=dfs2(v,S);
52     }printf("%d
",ans);
53     return 0;
54 }
原文地址:https://www.cnblogs.com/guapisolo/p/9785961.html