标签:style blog http color os io ar for div
题意:
给你一张n个点n-1或n条边的带权无向图。从每个点出发一直走下去,不能重复经过某个点。问走过的路径长度的数学期望是多少?
N<=100000。图中至多只有一个环,并且环长不超过20。
题解:
首先考虑是一颗树的情况:
首先随便取一个点为根(例如1号点),做树状动规。
设点i走向它的子树的期望长度为F[i],i的子节点为s1、s2……sk。
设D[i] = ∑( F[sj] + edge(i,sj) ) ,那么F[i] = D[i] / k。
设P[i]为i作为起点的期望长度,那么P[1]=F[1],Du[i]是节点i的度数。
再进行一次DFS,如果y是x的子节点,P[x]已经算出。
设节点y向x走对期望的贡献是other,other=(P[x]*Du[x]-edge(x,y)-F[x])/(Du[x]-1)+edge(x,y)
P[y]=(other+D[y])/Du[y]
这样通过两次DFS,就可以算出所有点的P值。
但是这个题可能是一颗基环树。
首先可以通过dfs找出这个环,如果去掉这个环,那就是一些子树构成的森林。
首先用前面提到的树形动规的方法处理这些子树,求出D和F。
然后注意到环上的点很少,我们就依次让环上的每个点作为起点计算一遍。
对于环上的点x,设calc_pre(x)为从x向环上左侧走得到的期望长度,calc_nxt(x)为从x向环上右侧走得到的期望长度。
sx为x的孩子。
那么P[x]=(∑(F[sx]+edge(x,sx)+calc_pre(x)+calc_nxt(x))/Du(x)。
其中calc_pre,calc_nxt可以O(环上点个数)复杂度求出。
于是就可以再次dfs算出所有点的P。
ans=(∑P[i])/n
/************************************************************** Problem: 2878 User: zrts Language: C++ Result: Accepted Time:588 ms Memory:10748 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> //by zrt //problem: using namespace std; typedef long long LL; const int inf(0x3f3f3f3f); const double eps(1e-9); bool oncircle[100005]; int du[100005]; int fa[100005]; int H[100005],X[200005],P[200005],tot; double E[200005]; inline void add(int x,int y,int z){//add an edge P[++tot]=y;X[tot]=H[x];H[x]=tot;E[tot]=z; } int n,m; double F[100005];//for son E double D[100005];// F * |son| double p[100005];// ans int num[100005];// |son| int pre[100005]; double wpre[100005]; bool type; void treedp1(int x){//Dp the tree first for(int i=H[x];i;i=X[i]){ if(P[i]==fa[x]||oncircle[P[i]]) continue; fa[P[i]]=x; treedp1(P[i]); D[x]+=F[P[i]]+E[i];num[x]++; } if(num[x]) F[x]=D[x]/num[x]; else F[x]=0; } void treedp2(int x,double edge){//Dp the tree second | calc the P double other; if(!fa[fa[x]]) { if(!type){ if(num[fa[x]]>1) other=(p[fa[x]]*(num[fa[x]]+0)-edge-F[x])/(num[fa[x]]-1)+edge; else other=edge; }else{ other=(p[fa[x]]*(num[fa[x]]+2)-edge-F[x])/(num[fa[x]]+1)+edge; } } else other=(p[fa[x]]*(num[fa[x]]+1)-edge-F[x])/num[fa[x]]+edge; p[x]=(other+D[x])/(num[x]+1); for(int i=H[x];i;i=X[i]){ if(P[i]==fa[x]||oncircle[P[i]]) continue; treedp2(P[i],E[i]); } } vector<int> circle; bool ok; int nxt[100005];double wnxt[100005]; void findcircle(int x,int fa){ for(int i=H[x];i;i=X[i]){ if(P[i]==fa) continue; if(pre[P[i]]){ ok=1; int k=x; pre[P[i]]=x; wpre[P[i]]=E[i]; do{ oncircle[k]=1; circle.push_back(k); k=pre[k]; }while(k!=P[i]); oncircle[k]=1; circle.push_back(k); }else{ pre[P[i]]=x;wpre[P[i]]=E[i]; findcircle(P[i],x); if(ok) return; } } } double calc_nxt(int now,int end){ double ret=wnxt[now]; now=nxt[now]; int extra=0; if(nxt[now]!=end) ret+=calc_nxt(now,end)/(du[now]-1); else extra=-1; for(int i=H[now];i;i=X[i]){ if(oncircle[P[i]]) continue; ret+=(E[i]+F[P[i]])/(du[now]-1+extra); } return ret; } double calc_pre(int now,int end){ double ret=wpre[now]; now=pre[now]; int extra=0; if(pre[now]!=end) ret+=calc_pre(now,end)/(du[now]-1); else extra=-1; for(int i=H[now];i;i=X[i]){ if(oncircle[P[i]]) continue; ret+=(E[i]+F[P[i]])/(du[now]-1+extra); } return ret; } int main(){// the main function #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif scanf("%d%d",&n,&m); for(int i=0,x,y,z;i<m;i++){ scanf("%d%d%d",&x,&y,&z); du[x]++; du[y]++; add(x,y,z); add(y,x,z); } if(m==n-1){ treedp1(1); p[1]=F[1]; for(int i=H[1];i;i=X[i]){ treedp2(P[i],E[i]); } double ans=0; for(int i=1;i<=n;i++){ ans+=p[i]; } printf("%.5f\n",ans/n); }else{ type=1; pre[1]=-1; findcircle(1,-1); for(int now=0;now<circle.size();now++){ nxt[pre[circle[now]]]=circle[now]; wnxt[pre[circle[now]]]=wpre[circle[now]]; } for(int now=0;now<circle.size();now++){ for(int i=H[circle[now]];i;i=X[i]){ if(oncircle[P[i]]) continue; treedp1(P[i]); p[circle[now]]+=(F[P[i]]+E[i])/du[circle[now]]; num[circle[now]]++; } } for(int now=0;now<circle.size();now++){ p[circle[now]]+=(calc_pre(circle[now],circle[now])+calc_nxt(circle[now],circle[now]))/du[circle[now]]; } for(int now=0;now<circle.size();now++){ for(int i=H[circle[now]];i;i=X[i]){ if(oncircle[P[i]]) continue; fa[P[i]]=circle[now]; treedp2(P[i],E[i]); } } double ans=0; for(int i=1;i<=n;i++){ ans+=p[i]; } printf("%.5f\n",ans/n); } return 0; }
标签:style blog http color os io ar for div
原文地址:http://www.cnblogs.com/zrts/p/bzoj2878.html