题目简意:一个节点能覆盖距离为2的节点,问至少选择多少节点能覆盖整棵树
思路:贪心和dp都可以,考虑dp
函数 | 意义 | 备注 |
dp[i][0] | 在i处设置消防站,这样能覆盖到i,i的所有儿子,i的所有孙子,i的父亲,i的爷爷,i的所有兄弟 | |
dp[i][1] | 在i某个儿子处设置消防站 | |
dp[i][2] | 在i某个孙子处设置消防站 | dp[i][0,1,2]能保证将i覆盖 |
dp[i][3] | 能将所有的i的儿子覆盖的方案数 | |
dp[i][4] | 能将所有的i的孙子覆盖的方案数 | dp[i][3,4]不能保证将i覆盖 |
递推公式以及优化:
可以愉快的coding了:
n=int(input())
tree=[[] for i in range(n+1)]
for i in range(2,n+1):
aa=int(input())
tree[aa].append(i)
tree[i].append(aa)
debug=0
if debug==1:print(tree)
dp=[[0 for i in range(5)]for i in range(n+1)]
inf=float("inf")
def dfs(x,fa):
dp[x][0]=1
vis=0
mid1=inf
mid2=inf
for i in tree[x]:
if i==fa:continue
vis=1
dfs(i,x)
dp[x][0]+=dp[i][4]
dp[x][1]+=dp[i][3]
dp[x][2]+=dp[i][2]
dp[x][3]+=dp[i][2]
dp[x][4]+=dp[i][3]
mid1=min(mid1,dp[i][0]-dp[i][3])
mid2=min(mid2,dp[i][1]-dp[i][2])
if vis==0:
dp[x][0]=1
dp[x][1]=1
dp[x][2]=1
return
else:
dp[x][1]+=mid1
dp[x][2]+=mid2
for i in range(1,5):
dp[x][i]=min(dp[x][i],dp[x][i-1])
dfs(1,-1)
print(dp[1][2])