树上随机游走
问题描述
给定一颗树,树上有一点,每一时刻都会等概率地移动至邻接节点上,求该点移动至某一点的期望距离。
定义
T = ( V , E ) : T = ( V , E ) : 所讨论的树;
d ( u ) : u d ( u ) : u 节点的度数;
w ( u , v ) : u w ( u , v ) : u 结点与 v v 结点之间的边的边权;
s i z e ( u ) : u s i z e ( u ) : u 结点的子树大小;
p u : u p u : u 结点的父节点;
s o n u : u s o n u : u 结点的子节点集合;
s i b l i n g u : u s i b l i n g u : u 结点的兄弟结点集合。
向父结点走的期望距离
设 f ( u ) f ( u ) 代表 u u 结点走到其父结点 p u p u 的期望距离,则有:
f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) + f ( u ) ) d ( u ) f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) + f ( u ) ) d ( u )
分子中的前半部分代表直接走向了父结点的距离;后半部分代表先走向了子结点,再由子结点走回来然后再向父结点走的距离。
从 u u 结点走向其任何邻接点的概率相同,所以总体除以 d ( u ) d ( u ) 。
将上式右边和式中的 f ( u ) f ( u ) 提出来:
f ( u ) = w ( u , p u ) + ( d ( u ) − 1 ) ⋅ f ( u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) ) d ( u ) f ( u ) = w ( u , p u ) + ( d ( u ) − 1 ) ⋅ f ( u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) ) d ( u )
两边同乘 d ( u ) d ( u ) ,则有:
d ( u ) ⋅ f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) ) + ( d ( u ) − 1 ) ⋅ f ( u ) d ( u ) ⋅ f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) ) + ( d ( u ) − 1 ) ⋅ f ( u )
两边同减 ( d ( u ) − 1 ) ⋅ f ( u ) ( d ( u ) − 1 ) ⋅ f ( u ) 得:
f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) ) f ( u ) = w ( u , p u ) + ∑ v ∈ s o n u ( w ( u , v ) + f ( v ) )
再将权值,即 w w 整合至一个和式得:
f ( u ) = ∑ ( u , s ) ∈ E w ( u , s ) + ∑ v ∈ s o n u f ( v ) f ( u ) = ∑ ( u , s ) ∈ E w ( u , s ) + ∑ v ∈ s o n u f ( v )
我们将这个式子设为 ( 1 ) ( 1 ) 式,下文需要用到。
叶结点的初始值为 1 1 ,即 f ( l e a f ) = 1 f ( l e a f ) = 1 (因为它只能直接向父结点走)。
特别地,当边权全部为 1 1 时,上式可化简为:
f ( u ) = d ( u ) + ∑ v ∈ s o n u f ( v ) f ( u ) = d ( u ) + ∑ v ∈ s o n u f ( v )
即 u u 子树的所有结点的度数和,同时也是 2 ⋅ s i z e ( u ) − 1 2 ⋅ s i z e ( u ) − 1 ,因为除 u u 与 p u p u 之间的边只有 1 1 点贡献以外,每条边会产生 2 2 点度数的贡献(一去一回走两次),而每个结点连向其父亲的边有且只有一条,所以就是 2 ⋅ s i z e ( u ) − 1 2 ⋅ s i z e ( u ) − 1 。
向子节点走的期望距离
我们再设 g ( u ) g ( u ) 代表从 u u 结点的父节点 p u p u 走到 u u 结点的期望距离。注意看清楚,g ( u ) g ( u ) 不是代表从 u u 结点走向其子结点的期望距离。
易得:
g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + g ( u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) + g ( u ) ) d ( p u ) g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + g ( u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) + g ( u ) ) d ( p u )
分子中的第一部分代表从 p u p u 直接走向了结点 u u ;第二部分代表先走向了 p p u p p u 再走回来,然后再向 u u 结点走;第三部分代表先走向 u u 结点的兄弟结点再走回来,然后再向 u u 结点走。
从 p u p u 结点走向其任何邻接点的概率相同,所以总体再除以 d ( p u ) d ( p u ) 。
上式左右两边同乘 d ( p u ) d ( p u ) 得:
d ( p u ) ⋅ g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + g ( u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) + g ( u ) ) d ( p u ) ⋅ g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + g ( u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) + g ( u ) )
右边和式中共有 d ( p u ) − 2 d ( p u ) − 2 个 g ( u ) g ( u ) ,和式外还有一个 d ( u ) d ( u ) ,所以等式左右两边同时减去 ( d ( p u ) − 1 ) ⋅ g ( u ) ( d ( p u ) − 1 ) ⋅ g ( u ) 得:
g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) ) g ( u ) = w ( u , p u ) + w ( p u , p p u ) + g ( p u ) + ∑ v ∈ s i b l i n g u ( w ( p u , v ) + f ( v ) )
将所有的权值,即 w w 合并到一个和式,得:
g ( u ) = g ( p u ) + ∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v ) g ( u ) = g ( p u ) + ∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v )
我们将这个式子设为 ( 2 ) ( 2 ) 式,下文也需要用到。
再将刚刚得到的 ( 1 ) ( 1 ) 式:
f ( u ) = ∑ ( u , s ) ∈ E w ( u , s ) + ∑ v ∈ s o n u f ( v ) f ( u ) = ∑ ( u , s ) ∈ E w ( u , s ) + ∑ v ∈ s o n u f ( v )
转化成
∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v ) + f ( u ) = f ( p u ) ∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v ) + f ( u ) = f ( p u )
即
∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v ) = f ( p u ) − f ( u ) ∑ ( p u , s ) ∈ E w ( p u , s ) + ∑ v ∈ s i b l i n g u f ( v ) = f ( p u ) − f ( u )
再带入 ( 2 ) ( 2 ) 式得:
g ( u ) = g ( p u ) + f ( p u ) − f ( v ) g ( u ) = g ( p u ) + f ( p u ) − f ( v )
根节点的初始值设为 0 0 ,即 g ( r o o t ) = 0 g ( r o o t ) = 0 。
下面是代码(以无权树为例)
void dfs1 (int u, int p_u) {
f[u] = edge[u].size ();
for (int i = 0 ; i < edge[u].size (); ++ i) {
int v = edge[u][i];
if (v == p_u)
continue ;
dfs1 (v, u);
f[u] += f[v];
}
}
void dfs2 (int u, int p_u) {
if (u != root)
g[u] = g[p_u] + f[p_u] - f[u];
for (int i = 0 ; i < edge[u].size (); ++ i) {
int v = edge[u][i];
if (v == p_u)
continue ;
dfs2 (v, u);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现