BZOJ2878 loj2673 洛谷P2081 [Noi2012]迷失游乐园【树形dp(基环树)】

传送门


SOL

题意:给一个可能有一个环的树,定义一条合法的路径为从某一起点出发,随机在未走过的点中选择,直到走不动。求从任一点出发的路径长度的期望值。

//基环树的确不需要学啊。。。自己yy就出来了。


一、先处理树上的情况。
这是一个很显然的树上期望dp,但是为了保证统计的方案是合法的,我们要把向上走和向下走两种情况分开讨论。

d p [ u ] [ d o w n ] = ( ∑ d p [ s o n [ u ] [ d o w n ] ) / s [ u ] dp[u][down]=(\sum dp[son[u][down])/s[u] dp[u][down]=(dp[son[u][down])/s[u]

d p [ u ] [ u p ] = ( d p [ f a [ u ] [ d o w n ] ∗ s [ f a [ u ] ] − l e n [ f a [ u ] ] [ u ] − d p [ u ] [ d o w n ] + d p [ f a [ u ] [ u p ] ) / ( s [ f a [ u ] ] + 1 ) dp[u][up]=(dp[fa[u][down]*s[fa[u]]-len[fa[u]][u]-dp[u][down]+dp[fa[u][up])/(s[fa[u]]+1) dp[u][up]=(dp[fa[u][down]s[fa[u]]len[fa[u]][u]dp[u][down]+dp[fa[u][up])/(s[fa[u]]+1)
s [ u ] s[u] s[u]: u u u的儿子数量 , d p [ u ] [ d o w n ] dp[u][down] dp[u][down] u u u向下走的期望值。

二、再处理环上的情况。
由于从 i i i点出发不能回到自己,首先要分成顺时针和逆时针,并且要以环上每一点为起点出发讨论情况。由于环上点数 ≤ 20 \le20 20,极端情况下时间复杂度为 1 e 5 / 20 ∗ 20 ∗ 20 = 2 e 6 1e5/20*20*20=2e6 1e5/202020=2e6 ,可以承受.
f [ u ] [ 0 ] = l e n [ u ] [ v ] + f [ v ] [ 0 ] f[u][0]=len[u][v]+f[v][0] f[u][0]=len[u][v]+f[v][0]
t m p [ u ] [ 0 ] = ( d p [ u ] [ 0 ] ∗ s [ u ] + t m p [ v ] [ 0 ] + l e n [ u ] [ v ] ) / ( s [ u ] + 1 ) tmp[u][0]=(dp[u][0]*s[u]+tmp[v][0]+len[u][v])/(s[u]+1) tmp[u][0]=(dp[u][0]s[u]+tmp[v][0]+len[u][v])/(s[u]+1)

f [ u ] f[u] f[u]为当前起点, t m p [ u ] tmp[u] tmp[u]为中间点。

三、合并情况。

i f ( ! f a [ u ] )   n o w = ( f [ u ] [ 1 ] + f [ u ] [ 0 ] + d p [ u ] [ 0 ] ∗ s [ u ] ) / ( 1.0 ∗ ( s [ u ] + 2 ) ) ; if(!fa[u])\ now=(f[u][1]+f[u][0]+dp[u][0]*s[u])/(1.0*(s[u]+2)); if(!fa[u]) now=(f[u][1]+f[u][0]+dp[u][0]s[u])/(1.0(s[u]+2));
e l s e   n o w = ( d p [ u ] [ 1 ] + d p [ u ] [ 0 ] ∗ s [ u ] ) / ( 1.0 ∗ ( s [ u ] + 1 ) ) else \ now=(dp[u][1]+dp[u][0]*s[u])/(1.0*(s[u]+1)) else now=(dp[u][1]+dp[u][0]s[u])/(1.0(s[u]+1))


//DP式子写起来真累。。


CODE

#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
using namespace std;
cs int N=1e5+10;
db f[N][2],dp[N][2],tmp[N][2];
int n,m,s[N],fa[N],CN,nxt[N<<1],head[N],w[N<<1],to[N<<1],cnt=1,lasw[N],len[N][2],nxtp[N][2];
bool vis[N],rod[N<<1];
vector <int> g[N];
inline void _add(int u,int v,int ww){
	nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;w[cnt]=ww;
}
void dfs1(int u){
	vis[u]=1;
	for(int i=head[u];i;i=nxt[i]){
		if(rod[i])continue;
		rod[i]=rod[i^1]=1;
		if(vis[to[i]]){
			nxtp[to[i]][0]=u;nxtp[u][1]=to[i];
			len[to[i]][0]=len[u][1]=w[i];
			++CN;
			for(int v=u;;v=fa[v]){
				g[CN].push_back(v);
				if(v==to[i])break;
				nxtp[v][0]=fa[v];nxtp[fa[v]][1]=v;
				len[v][0]=len[fa[v]][1]=lasw[v];
			}
		}
		else{
			lasw[to[i]]=w[i];
			fa[to[i]]=u;
			dfs1(to[i]);
		}
	}
}
void dfs(int u,bool kd){
	if(kd==1){
		if(fa[u]){
			if(fa[fa[u]])
				dp[u][1]=(dp[fa[u]][0]*s[fa[u]]-dp[u][0]-lasw[u]+dp[fa[u]][1])/(1.0*(s[fa[u]]))+lasw[u];
			else
				dp[u][1]=(dp[fa[u]][0]*s[fa[u]]-dp[u][0]-lasw[u]+f[fa[u]][0]+f[fa[u]][1])/(1.0*(s[fa[u]]+1))+lasw[u];
		}
	}
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(v==fa[u]||vis[v])continue;
		fa[v]=u;lasw[v]=w[i];
		dfs(v,kd);
		if(kd==0){
			++s[u];
			dp[u][0]+=dp[v][0]+w[i];	
		}
	}
	if(kd==0&&s[u])dp[u][0]/=(1.0*(s[u]));
}
namespace work1{
	inline void dfs(int u,bool kd){
		if(kd==1){
			if(fa[u]){
				dp[u][1]=lasw[u];
				if(fa[fa[u]])
					dp[u][1]+=(dp[fa[u]][0]*s[fa[u]]-dp[u][0]-lasw[u]+dp[fa[u]][1])/(1.0*(s[fa[u]]));
				else
					if(s[fa[u]]>1)dp[u][1]+=(dp[fa[u]][0]*s[fa[u]]-dp[u][0]-lasw[u])/(1.0*(s[fa[u]]-1));							
			}
		}
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i];
			if(v==fa[u]||vis[v])continue;
			fa[v]=u;lasw[v]=w[i];
			dfs(v,kd);
			if(kd==0){
				++s[u];
				dp[u][0]+=dp[v][0]+w[i];	
			}
		}
		if(kd==0&&s[u])dp[u][0]/=(1.0*(s[u]));
	}
	inline void gather(){
		db now=0,ans=0;
		for(int u=1;u<=n;++u){
			if(!fa[u])
				now=dp[u][0];
			else
				now=(dp[u][1]+dp[u][0]*s[u])/(1.0*(s[u]+1));
			ans+=now/(1.0*n);
		}
		pf("%.5lf",ans);
	}	
}
inline void calc(int u,cs int &bord,cs int &kd){
	if(nxtp[u][kd]==bord){
		tmp[u][kd]=dp[u][0];
		return;
	}
	calc(nxtp[u][kd],bord,kd);
	if(u^bord)tmp[u][kd]=(dp[u][0]*s[u]+len[u][kd]+tmp[nxtp[u][kd]][kd])/(1.0*(s[u]+1));
	else f[u][kd]=len[u][kd]+tmp[nxtp[u][kd]][kd];
}
inline void gather(){
	db now=0,ans=0;
	for(int u=1;u<=n;++u){
		if(!fa[u])
			now=(f[u][1]+f[u][0]+dp[u][0]*s[u])/(1.0*(s[u]+2));
		else
			now=(dp[u][1]+dp[u][0]*s[u])/(1.0*(s[u]+1));
		//cout<<u<<' '<<now<<'\n';
		ans+=now/(1.0*n);
	}
	pf("%.5lf",ans);
}
signed main (){
//	freopen("data.in","r",stdin);
	sf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int u,v,w;sf("%d%d%d",&u,&v,&w);
		_add(u,v,w);_add(v,u,w);
	}
	if(m^n){
		work1::dfs(1,0);
		work1::dfs(1,1);
		work1::gather();
		return 0;
	}	
	for(int u=1;u<=n;++u)if(!vis[u])dfs1(u);
	memset(vis,0,sizeof vis);
	for(int i=1;i<=CN;++i){
		int up=g[i].size();
		for(int j=0;j<up;++j){
			fa[g[i][j]]=0;vis[g[i][j]]=1;
		}
		for(int j=0;j<up;++j){
			dfs(g[i][j],0);
		}
		for(int j=0;j<up;++j){
			calc(g[i][j],g[i][j],0);
			calc(g[i][j],g[i][j],1);
			dfs(g[i][j],1);
		}
	}
	gather();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值