2023河南萌新联赛第(六)场:河南理工大学 C 旅游

题目大意 : 题目大意: 题目大意:
给定一棵 n 个节点的树,点之间有长度为 1 的路径,求起始点为任意点时走的路径长度的期望最大值 给定一棵n个节点的树,点之间有长度为1的路径,求起始点为任意点时走的路径长度的期望最大值 给定一棵n个节点的树,点之间有长度为1的路径,求起始点为任意点时走的路径长度的期望最大值 (不会走重复的边,且走每一条边的概率一致 ) (不会走重复的边,且走每一条边的概率一致) (不会走重复的边,且走每一条边的概率一致)
题目分析 : 题目分析: 题目分析:
可以考虑换根 D P , 设 d p x 表示从 x 开始向下走经过节点数的期望 可以考虑换根DP,设dp_x表示从x开始向下走经过节点数的期望 可以考虑换根DP,dpx表示从x开始向下走经过节点数的期望
易知 d p x = 1 + 1 ∣ s o n x ∣ ∑ s ∈ s o n x d p s 易知dp_x=1+\frac{1}{ \left\vert son_x\right\vert }\sum_{s\in son_x}dp_s 易知dpx=1+sonx1ssonxdps
接下来,可以设 g x 表示以 x 为起始点的期望 接下来,可以设g_x表示以x为起始点的期望 接下来,可以设gx表示以x为起始点的期望
由于我们计算 d p 数组时必以一点为根节点,不妨为 1 , 记算完 d p 数组后,那么 g 1 = d p 1 由于我们计算dp数组时必以一点为根节点,不妨为1,记算完dp数组后,那么g_1=dp_1 由于我们计算dp数组时必以一点为根节点,不妨为1,记算完dp数组后,那么g1=dp1
接下来便考虑换根 D P , 对于 v ,我们假设已知 v 的父亲的值 g u ,首先考虑 v 的子树内的贡献,可知贡献为 ∑ s ∈ s o n v d p s , 由 d p 式子的变形可知 ∑ s ∈ s o n v d p s = ( d p v − 1 ) ∗ ∣ s o n v ∣ , 显然可以 O ( 1 ) 求出 接下来便考虑换根DP,对于v,我们假设已知v的父亲的值g_u,首先考虑v的子树内的贡献,可知贡献为\sum_{s\in son_v}dp_s,由dp式子的变形可知\sum_{s\in son_v}dp_s=(dp_v-1)*\left\vert son_v\right\vert,显然可以O(1)求出 接下来便考虑换根DP,对于v,我们假设已知v的父亲的值gu,首先考虑v的子树内的贡献,可知贡献为ssonvdps,dp式子的变形可知ssonvdps=(dpv1)sonv,显然可以O(1)求出
再考虑 v 的父节点的贡献,可知贡献为 ∣ s o n u + 1 ∣ ∗ g u − d p v − 1 ∣ s o n u ∣ 再考虑v的父节点的贡献,可知贡献为\frac{\left\vert son_u+1\right\vert*g_u-dp_v-1}{\left\vert son_u\right\vert} 再考虑v的父节点的贡献,可知贡献为sonusonu+1gudpv1
最后还有 v 对自己的贡献 1 最后还有v对自己的贡献1 最后还有v对自己的贡献1
故可以得出转移式 g v = 1 ∣ s o n v + 1 ∣ ∗ ( ( d p v − 1 ) ∗ ∣ s o n v ∣ + ∣ s o n u + 1 ∣ ∗ g u − d p v − 1 ∣ s o n u ∣ ) + 1 故可以得出转移式g_v=\frac{1}{\left\vert son_v+1\right\vert}*((dp_v-1)*\left\vert son_v\right\vert+\frac{\left\vert son_u+1\right\vert*g_u-dp_v-1}{\left\vert son_u\right\vert})+1 故可以得出转移式gv=sonv+11((dpv1)sonv+sonusonu+1gudpv1)+1
最后答案便为 m a x i = 1 n g i − 1 最后答案便为max_{i=1}^ng_i-1 最后答案便为maxi=1ngi1
时间复杂度为 O ( n ) 时间复杂度为O(n) 时间复杂度为O(n)
参考代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int M=100007;

int n;
vector<int> G[M];
double dp[M],g[M];

void DFS1(int now,int fa){
	int v;
	double sum=0;
	for(int i=0;i<G[now].size();i++){
		v=G[now][i];
		if(fa==v) continue;
		DFS1(v,now);
		sum+=dp[v];
	}
	if(now==1)dp[now]=1+sum/G[now].size();
	else if(G[now].size()==1) dp[now]++;
	else dp[now]=1+sum/(G[now].size()-1);
}

void DFS2(int now,int fa){
	int v;
	double sum;
	for(int i=0;i<G[now].size();i++){
		v=G[now][i];
		if(fa==v) continue;
		sum=0;
	    sum=sum+(dp[v]-1)*(G[v].size()-1);
	    if(G[now].size()>1) {
	    	sum=sum+(g[now]*G[now].size()-dp[v]-1)/(G[now].size()-1);
		}else {
			sum=sum+1;
		}
	    g[v]=sum/(G[v].size())+1;
		DFS2(v,now);
	}
}
int main(){
	ios::sync_with_stdio(false);
	int a,b;
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>a>>b;
		G[a].push_back(b);
		G[b].push_back(a);
    }
	DFS1(1,-1);g[1]=dp[1];
//	for(int i=1;i<=4;i++){
//		cout<<dp[i]<<" ";
//	}
//	cout<<"\n";
	DFS2(1,-1);
//	for(int i=1;i<=4;i++){
//		cout<<g[i]<<" ";
//	}
	double anq=0;
	for(int i=1;i<=n;i++) anq=max(anq,g[i]);
	cout<<fixed<<setprecision(3)<<anq-1<<"\n";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值