版权声明:虽然我很菜,不过转载请标明出处。 https://blog.csdn.net/Patrickpwq/article/details/86656560
见识了好多乱搞神仙
我是用树形DP做的 设dp[i]表示在i点的子树放多少个守卫
显然 有方程
if(mind[i]-(depth[i]-1)<=depth[i]) (其中mind表示i的子树内的叶子节点最浅的深度) dp[i]=1 即守卫可以抓到这个人
else dp[i]=Sigma{dp[i.son]}
#include<bits/stdc++.h>
const int N=100005;
using namespace std;
template<class T>
inline void read(T &x)
{
x=0;
static char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
}
int n,root;
struct Edge
{
int to,next;
}edge[2*N];
int first[N],tot;
inline void addedge(int x,int y)
{
tot++;
edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot;
}
int depth[N],mind[N],son[N],dp[N]; //dp[i]:在i点的子树放多少个守卫
void dfs1(int now,int fa)
{
son[now]=1;
depth[now]=depth[fa]+1;
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(vis==fa) continue;
dfs1(vis,now);
son[now]+=son[vis];
}
}
void dfs2(int now,int fa)
{
if(son[now]==1)
{
mind[now]=depth[now];
return;
}
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(vis==fa) continue;
dfs2(vis,now);
mind[now]=min(mind[now],mind[vis]);
}
}
void dfs3(int now,int fa)
{
if(son[now]==1)
{
dp[now]=1;
return;
}
bool flag=0;
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(vis==fa) continue;
dfs3(vis,now);
int ti=depth[now]-1; //走了多深就走了多久
int h=mind[now]-ti; //最屌的守卫的位置
if(h<=depth[now]) flag=1;
}
if(flag) dp[now]=1;
else
{
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(vis==fa) continue;
dp[now]+=dp[vis];
}
}
}
int main()
{
cin>>n>>root;
for(int i=1,u,v;i<=n-1;i++)
{
read(u); read(v);
addedge(u,v); addedge(v,u);
}
memset(mind,0x3f,sizeof(mind));
dfs1(root,0);
dfs2(root,0);
dfs3(root,0);
cout<<dp[root];
return 0;
}