题目链接: https://nanti.jisuanke.com/t/41392
题目大意:
以 1 1 1号节点作为根节点,假如当前节点有 m m m个子节点,就进行 m m m次等概率的选择下一个节点,直到叶子节点为止,问最后走到最深的叶子节点的概率。
解题思路:
树上的一个
d
p
dp
dp转移,直接考虑转移到合法的情况比较复杂,每次转移我们考虑转移不到合法节点的情况。
设
d
p
[
i
]
dp[i]
dp[i]表示
i
i
i号节点不能到达最深节点的概率 那么
i
i
i号节点能到达最深节点的概率就是
1
−
d
p
[
i
]
1-dp[i]
1−dp[i]
假设当前节点
u
u
u有
m
m
m个子节点,有
s
s
s个
不
可
能
不可能
不可能 到达最深的叶子节点
v
v
v。
那么转移到这
s
s
s个节点的概率就是:
d
p
[
u
]
=
(
1
−
(
∑
i
=
1
s
d
p
[
v
]
m
)
m
)
dp[u]=(1-(\frac{\sum \limits _{i=1}^{s} dp[v]} {m})^m)
dp[u]=(1−(mi=1∑sdp[v])m)
然后就是建边的时候建双向边,树形dp一下就可以了,最后的答案就是 1 − d p [ 1 ] 1-dp[1] 1−dp[1]
#include <bits/stdc++.h>
typedef long long ll;
#define int ll
#define pb push_back
using namespace std;
const int mod=(int)1e9+7;
int n,m;
const int maxn=(int)1e6+5;
int dp[maxn];
vector<int>v[maxn];
int dep[maxn];
int maxx=0;
void dfs(int now,int fa, int depth)
{
maxx=max(depth,maxx);
dep[now]=depth;
for(auto nxt:v[now])
{
if(nxt==fa)continue;
dfs(nxt,now,depth+1);
}
}
ll qpm(ll a,ll b,ll c)
{
ll res=1;
while(b)
{
if(b & 1)
{
res=(res*a)%c;
}
a=(a*a)%c;
b=b>>1;
}
return res;
}
int inv(int x)
{
return qpm(x,mod-2,mod);
}
void solve(int now,int fa)
{
int sum=0;
int num=0;
for(auto nxt:v[now])
{
if(nxt==fa)continue;
num++;
solve(nxt,now);
sum=(sum+dp[nxt])%mod;
}
if(num==0)
{
if(dep[now]==maxx)dp[now]=0;
else dp[now]=1;
return;
}
sum=(sum*inv(num))%mod;
dp[now]=qpm(sum,num,mod);
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n;
int x,y;
for(int i=1;i<=n-1;i++)
{
cin>>x>>y;
v[x].pb(y);
v[y].pb(x);
}
dfs(1,0,1);
//cout<<"!!!"<<endl;
memset(dp,0,sizeof(dp));
solve(1,0);
cout<<(1-dp[1]+mod)%mod<<endl;
return 0;
}