这道题虽然在洛谷上归类为动态规划(树形dp),然而思考后我们可以用贪心来解决这个问题。
由于我们得到的是一个树形结构,所以我们可以模拟出这么一棵树来,然后通过dfs求出树每一个叶子结点的深度(根节点深度最小为1)。注意用dfs求深度要记录下结点的父亲结点,后面有用。因为消防局可以扑灭和它所在城市距离为2的城市的火灾,所以我们贪心,将求出的最深的节点找到,然后通过fa数组寻找其爷爷结点,并将其标记下来。接着,我们利用search函数来把和该节点距离为2的所有节点都打上标记。然后再重复这个过程,直到所有的结点都被标记过为止。注意需要利用前向星链状结构存图。里面的head[x]指的是x与其他子节点连边的tot,nnext[i]指的是将这个tot跳到另一个tot上去,to[i]就是to的tot那条边得到和x相连的结点。最后为了防止只剩下1结点没有被染色,我们应当让depth[i]>=depth[pd]。还要处理有爷爷结点和没有爷爷节点的情况。
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1000+5;
int n;
int depth[maxn],head[maxn],to[maxn*2],nnext[maxn*2],fa[maxn];
int b[maxn],team[maxn];
int tot;
int s=0,t=0;
int ans=0;
void add(int x,int y)
{
tot++;
nnext[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void search(int x)
{
for(int i=head[x];i;i=nnext[i])
{
int now=to[i];
b[now]=true;
for(int j=head[now];j;j=nnext[j])
{
b[to[j]]=true;
}
}
}
void dfs(int x)
{
for(int i=head[x];i;i=nnext[i])
{
int y=to[i];
if(y==fa[x]) continue;
fa[y]=x;
depth[y]=depth[x]+1;
dfs(y);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int q;
cin>>q;
add(i+1,q);
add(q,i+1);
}
depth[1]=1;
dfs(1);
/* team[t]=1;
t++;
b[1]=true;*/
/* while(s!=t)
{
int now=team[s];
s++;
for(int i=head[now];i;i=nnext[i])
{
int x=to[i];
if(b[x]==false)
{
fa[x]=now;
depth[x]=depth[now]+1;
b[x]=true;
team[t]=x;
t++;
}
}
}*/
// int pd=1;
// memset(b,false,sizeof(b));
while(true)
{
bool ok=false;
int pd=1;
for(int i=1;i<=n;i++)
{
if(depth[i]>=depth[pd]&&b[i]==false)
{
pd=i;
ok=true;
}
}
if(ok==false)
{
break;
}
if(fa[fa[pd]]!=0)
{
search(fa[fa[pd]]);
}
else if(fa[pd]!=0)
{
search(fa[pd]);
}
else search(pd);
ans++;
}
/*
memset(b,false,sizeof(b));
for(int j=1;j<=n;j++)
{
if(depth[j]>md&&b[j]==false)
{
md=depth[j];
pd=j;
for(int i=1;i<=n;i++)
{
if(depth[i]==depth[pd]-2&&fa[fa[pd]]==i&&b[i]==false)
{
ans++;
b[i]=true;
b[pd]=true;
search(i);
break;
}
}
}
}*/
printf("%d",ans);
return 0;
}