题目描述
解题思路
由题意可知这是一个树型传染图,其中每一次只能感染一代也就是只能传递一层,而每一次的防控措施也只能切断一条,也就是每次传播只能切断一条两个结点的边。
这是由题给条件画出的传播图,初始状态下只有结点1被感染,第一次传播切断1和3之间的联系,感染了结点2,第二次传播切断结点2和结点4之间的联系感染了结点5,传播结束一共感染力1,2,5一共3个结点。所以我们只用依次递归计算每个结点最小的感染人数(深度优先计算),其中每一次切断一条路径就是把下一层的人数减一。
代码
根据输入创建树,也就是深度优先的邻接表
n,p=map(int,input().split())
linkedlist=[[] for _ in range(n+1)]
for _ in range(p):
x,y=map(int,input().split())
linkedlist[x].append(y)
linkedlist[y].append(x)
#linkedlist:[[], [2, 3], [1, 4, 5], [1, 6, 7], [2], [2], [3], [3]]
tree=[[] for _ in range(n+1)]
def createTree(root):
if len(linkedlist[root])!=0:
tree[root]=linkedlist[root]
for x in linkedlist[root]:
linkedlist[x].remove(root)
createTree(x)
createTree(1)
#tree:[[], [2, 3], [4, 5], [6, 7], [], [], [], []]
其中tree就是我们构建的树,tree[1]就表示以1为父节点连接了2,3两个子节点。
深度优先遍历
# 输入当前层结点和当前感染人数,计算从下一层开始的被感染的最少人数并返回人数
bestresult = 300
def dfs(currentlayer, currentcount):
global tree, bestresult
nextlayer = []
for x in currentlayer:
nextlayer += tree[x]
minnum = 300
# 到达叶子结点,更新bestresult
if nextlayer ==[]:
if currentcount<bestresult:
bestresult = currentcount
return 0
# 若感染人数大于bestresult则剪枝
elif currentcount + len(nextlayer)-1<=bestresult:
for i,x in enumerate(nextlayer):
del nextlayer[i]
nextnum = dfs(nextlayer, currentcount + len(nextlayer)-1)
if minnum>nextnum:
minnum = nextnum
nextlayer.insert(i,x)
#遍历完一颗子树,求得最小的感染数在加上下一层结点的数目减一就获得该父节点最小感染数
return len(nextlayer)-1+minnum
# 若大于则直接返回300(表示剪枝)
else:
return 300
#最后加的1是加上原本就被感染的根节点
print(dfs([1], 1)+1)