1617. 统计子树中城市之间最大距离

题目描述

有n个城市,编号是1-n,
给了一个数组edges表示了城市的连接关系,且每个城市间最多只有一条路(城市间的连接是树),
需要求一个结果ans,其中ans[i]表示城市间最大距离是i+1子树的数目

f1-状态压缩+动态规划

基本分析

  1. 城市个数不超过15可以暗示什么?用二进制表示当前城市的选择状态
  2. 怎么定义dp状态?dp[j]表示城市选择是j时候对应的最大距离
  3. 以上状态j一定都是合法的吗,怎么判断?j可能本身不能联通,(1)在利用j进行搭建的时候就判断一下,如果f[j]是0,表示不能搭建;(2)对需要枚举新增的节点i,看j+(1<<i)是不是能联通?做法是枚举j中的节点k,看是不是存在d[k][i]=1的点
  4. 怎么考虑转移?如果nj是联通的,这个时候就遍历j内的所有点,找出和i点距离最大的更新f[nj]
  5. 怎么取得最后的结果?f[j]的含子树是j时候的最大距离,那么遍历j,只要f[j]不等于0(对应单个点或者不成立的子树),f[j]-1的值就是ans的索引,累加ans[f[j]-1]就行

代码

class Solution:
def countSubgraphsForEachDiameter(self, n: int, edges: List[List[int]]) -> List[int]:
# 定义距离d
d = [[n+1]* n for _ in range(n)]
# 定义dp数组f
mask = 1<<n
f = [0] * mask
# 相同点的d值设置为0
for i in range(n):
for j in range(n):
if i == j:
d[i][j] = 0
# 遍历相邻点,初始化d和一部分子树
for x, y in edges:
d[x-1][y-1] = 1
d[y-1][x-1] = 1
f[(1<<(x-1)) + (1<<(y-1))] = 1
# Floyed初始化之间的最小距离
for k in range(n):
for i in range(n):
for j in range(n):
if d[i][k] != n+1 and d[k][j]!= n+1:
d[i][j] = min(d[i][j], d[i][k]+d[k][j])
# 遍历状态j
for j in range(1, mask):
# 去掉不是树的状态,通过f判断
if f[j] == 0:
continue
# 遍历可能能新增的节点i,对i的要求是i不在j中,且新状态没有被计算过
for i in range(n):
nj = j + (1<<i)
if j & (1<<i) != 0 or f[nj] != 0:
continue
# 遍历j,看是不是能连起来
for k in range(n):
if j & (1<<k) != 0 and d[k][i] ==1:
f[nj] = f[j]
break
# 如果新状态不能存在,不考虑i了
if f[nj] == 0:
continue
# 再次遍历j中的节点,来维护dp距离
for k in range(n):
if j & (1<<k) != 0:
f[nj] = max(f[nj], d[k][i])
# 统计结果
ans = [0] * (n-1)
for j in range(1, mask):
if f[j] != 0:
ans[f[j]-1] += 1
return ans

复杂度

时间:FloyedO(n3),O(n2),O(2nnn)
空间:O(n2),dpO(2n)

总结

  1. 几个边界需要注意:
  • (1)节点自身间的距离是
  • (2)相邻节点间的距离是1
  • (3)相邻节点构成了最小子树,对应的f值是1
  • (4)孤立的节点和不能成子树的节点组合对应的f值都是0
  • (5)判断一个组合j是不是有效,就是(1)先看对应的f值是不是0;(2)对可能的新组合nj,如果找不到k可以给nj赋值,那么nj还是0,再转移前就会退出当前对i的讨论
  1. 预处理的时候,用Floyed获取任意点间的最小距离
  2. 枚举状态的时候需要考虑:
  • (1)当前j可能是不合法的,这个时候就换下一个j,或者是合法的往下走;
  • (2)枚举需要扩展的节点i,对i的要求是<1>i不能被j包含+<2>j+i节点之前没有算过,如果满足以上要求,这个i才去判断是不是可以连接;
  • (3)怎么判断连接?j中存在一个点k和i的距离是1,如果没有的话怎么办?说明j+(1<<i)这个子树不成立,去找一下i;
  • (4)怎么更新状态,再次遍历j中的点k,每次取f[nj]和d[i][k]的最大值
  1. 求结果的时候就是遍历f,生成答案
posted @   zhangk1988  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示