游乐园"/>
BZOJ2878: [Noi2012]迷失游乐园
BZOJ2878: [Noi2012]迷失游乐园
树形Dp
题解:
orz orz orz orz
ORZ Tunix ORZ
orz orz orz orz
简单写一下,怕自己忘了。。。
先考虑没有环的情况。
令点1为树根,设 down[i] 表示从i开始向下走的期望步数, up[i] 表示往上走的。
down[i] 的计算很简单:
考虑 up[i] ,点i走到父亲f后,可以顺着其他的儿子向下走,也可以继续往上。所以:
最后,以每个点为出发点统计答案:
考虑环呢?注意最多只有一个环。
不在环上的点一样算,环上的down也一样算。
环上的点的up值其实就是沿着环走到其他的任意一个环上的点,然后再沿外向树向下走的期望长度。
这一段直接看代码吧。
for(int i=1;i<=tot;i++){int now=cir[i];double k=1;for(int x=nxt[now];x!=now;x=nxt[x]){if(nxt[x]!=now)up[now]+=k*(len[id[pre[x]]][id[x]]+down[x]*son[x]/(son[x]+1));elseup[now]+=k*(len[id[pre[x]]][id[x]]+down[x]);k/=(son[x]+1);}k=1;for(int x=pre[now];x!=now;x=pre[x]){if(pre[x]!=now)up[now]+=k*(len[id[nxt[x]]][id[x]]+down[x]*son[x]/(son[x]+1));elseup[now]+=k*(len[id[nxt[x]]][id[x]]+down[x]);k/=(son[x]+1);}up[now]/=2;
}
两个并列的循环分别是顺时针、逆时针,最后/2。k是走到这个点的概率,每次乘以 1son[x]+1 .
另外环上的点算是有两个父亲,于是定义 pa[i] 表示i的父亲个数,则 up[i] 的式子化为:
注意除0!
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 100005;int n,m,flag,tot; double up[N],down[N]; bool bo[N];
int len[21][21],cir[21],id[N],pre[N],nxt[N],fa[N],son[N];struct Edge{int to,next,w;
} e[N*2];
int head[N], ec=0;
void add(int a,int b,int w){ec++; e[ec].to=b; e[ec].w=w;e[ec].next=head[a]; head[a]=ec;
}void findcir(int u,int f){bo[u]=true;for(int i=head[u];i;i=e[i].next){int v=e[i].to; if(v==f) continue;if(bo[v]){ flag=v; return; }findcir(v,u);if(flag>0){if(flag==u) flag=-1;return;}if(flag==-1) break;}bo[u]=false;
}void dfscir(int u,int f){if(id[u]) return;id[u]=++tot; cir[tot]=u; fa[u]=2;for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(v==f) continue;if(!bo[v]) continue;nxt[u]=v; pre[v]=u;dfscir(v,u);len[id[u]][id[v]]=len[id[v]][id[u]]=e[i].w;break;}
} void dfsdown(int u,int f){for(int i=head[u];i;i=e[i].next){int v=e[i].to;if(v==f || bo[v]) continue;fa[v]=1; dfsdown(v,u);son[u]++; down[u]+=down[v]+e[i].w;}if(son[u]) down[u]/=son[u];
}void dfsup(int u,int f,int w){up[u]=w;if(son[f]+fa[f]>1){up[u]+=(up[f]*fa[f]+son[f]*down[f]-down[u]-w)/(son[f]+fa[f]-1);}for(int i=head[u];i;i=e[i].next){if(e[i].to!=f) dfsup(e[i].to,u,e[i].w);}
}int main(){freopen("a.in","r",stdin);freopen("a.out","w",stdout);cin>>n>>m; int a,b,w;for(int i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&w);add(a,b,w); add(b,a,w);}if(m<n){dfsdown(1,0);for(int i=head[1];i;i=e[i].next)dfsup(e[i].to,1,e[i].w);}else{findcir(1,0);// for(int i=1;i<=n;i++) if(bo[i]) D(i); E;for(int i=1;i<=n;i++){if(bo[i]){ dfscir(i,0); break; }}// for(int i=1;i<=n;i++){ if(bo[i]){ D(i); D(pre[i]); D(nxt[i]); E; } }for(int i=1;i<=tot;i++){ dfsdown(cir[i],0); }for(int i=1;i<=tot;i++){int now=cir[i];double k=1;for(int x=nxt[now];x!=now;x=nxt[x]){if(nxt[x]!=now)up[now]+=k*(len[id[pre[x]]][id[x]]+down[x]*son[x]/(son[x]+1));elseup[now]+=k*(len[id[pre[x]]][id[x]]+down[x]);k/=(son[x]+1);}k=1;for(int x=pre[now];x!=now;x=pre[x]){if(pre[x]!=now)up[now]+=k*(len[id[nxt[x]]][id[x]]+down[x]*son[x]/(son[x]+1));elseup[now]+=k*(len[id[nxt[x]]][id[x]]+down[x]);k/=(son[x]+1);}up[now]/=2;}for(int j=1;j<=tot;j++){for(int i=head[cir[j]];i;i=e[i].next)if(!id[e[i].to]) dfsup(e[i].to,cir[j],e[i].w);}}// for(int i=1;i<=n;i++) D(down[i]), E;
// for(int i=1;i<=n;i++) D(up[i]), E;double ans=0;for(int i=1;i<=n;i++) ans+=(up[i]*fa[i]+down[i]*son[i])/(fa[i]+son[i]);printf("%.5f\n",ans/n);
}
更多推荐
BZOJ2878: [Noi2012]迷失游乐园
发布评论