题目大意:给你一棵有n个点的树,标记任意一个节点会使得与它距离为2及以内的节点被覆盖,现在问你最少标记几个节点就可以覆盖整棵树。
这道题可以dp和贪心,这里讲贪心的做法。
每次考虑深度最大的节点,肯定要在它、它的父亲、它的爷爷中选一个点标记,显然选爷爷能够覆盖最多的点,贪心的标记爷爷即可。
代码如下:
#include <cstdio>
#include <cstring>
struct node{int x,y,next;};
node e[2010];
struct nod{int x,fa,ye;};
nod tree[1010];
int n,len=0,t=0;
int first[1010];
bool v[1010];
void buildroad(int x,int y)
{
len++;
e[len].x=x;
e[len].y=y;
e[len].next=first[x];
first[x]=len;
len++;
e[len].x=y;
e[len].y=x;
e[len].next=first[y];
first[y]=len;
}
void bfs()
{
int st=1,ed=1,q[1010];
q[ed++]=1;
tree[++t].x=1;
tree[t].fa=tree[t].ye=0;
while(st!=ed)
{
int x=q[st];
for(int i=first[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==tree[st].fa)continue;
tree[++t].x=y;
tree[t].fa=q[st];
tree[t].ye=tree[st].fa;
q[ed++]=y;
}
st++;
}
}
void dfs(int x,int y,int z)
{
if(z==0)return;
for(int i=first[x];i;i=e[i].next)
{
int yy=e[i].y;
if(yy==y)continue;
v[yy]=true;
dfs(yy,x,z-1);
}
}
int main()
{
scanf("%d",&n);
memset(first,0,sizeof(first));
for(int i=2;i<=n;i++)
{
int x;
scanf("%d",&x);
buildroad(x,i);
}
bfs();
int wei=n;
memset(v,false,sizeof(v));
int ans=0;
while(wei>0)
{
ans++;
int x=tree[wei].ye;
if(x==0||x==1)break;
dfs(x,0,2);
v[x]=true;
while(v[tree[wei].x])wei--;
}
printf("%d",ans);
}