1. 程式人生 > >[BZOJ2878][NOI2012]迷失遊樂園(環套樹DP+概率)

[BZOJ2878][NOI2012]迷失遊樂園(環套樹DP+概率)

推薦講解:https://www.cnblogs.com/Tunix/p/4561493.html

首先考慮樹的情況,就是經典的樹上概率DP。先DP出down表示從這個點向兒子走能走的期望長度,再DP出up表示向父親走的期望長度,注意算up的時候要注意消除原先此點對父親的down的影響。

再考慮環的情況,由於環上點不超過20個,所以怎麼暴力DP都好,算出up後down用同樣的方法DP即可。

概率遞推式比較多,主要考慮好各種點的情況(樹根,非樹根,環上點,環外點,葉子)。

再注意下式子裡如果某項分母為0則忽略這項。

剩下的就是心態穩健地除錯了。

 1 #include<cstdio>
 2
#include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 7 typedef long long ll; 8 using namespace std; 9 10 const int N=200010; 11 bool d[N]; 12 int n,m,cnt,tim,tot,u,v,w,a[N],b[N],fa[N],pre[N],cf[N],dfn[N];
13 int son[N],h[N],nxt[N<<1],to[N<<1],val[N<<1]; 14 double ans,dn[N],up[N]; 15 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; } 16 int F(int x){ return x-1+((x==1)?tot:0); } 17 18 void Dn(int x,int fa){ 19 dn[x]=0; 20 For(i,x) if ((k=to[i])!=fa && !d[k])
21 son[x]++,Dn(k,x),dn[x]+=dn[k]+val[i]; 22 if (son[x]) dn[x]/=son[x]; 23 } 24 25 void Up(int x,int c){ 26 up[x]=c; 27 if (son[fa[x]]-1+cf[fa[x]]) up[x]+=(son[fa[x]]*dn[fa[x]]-dn[x]-c+up[fa[x]]*cf[fa[x]])/(son[fa[x]]-1+cf[fa[x]]); 28 For(i,x) if ((k=to[i])!=fa[x]) fa[k]=x,Up(k,val[i]); 29 } 30 31 void dfs(int x){ 32 dfn[x]=++tim; 33 For(i,x) if ((k=to[i])!=fa[x]){ 34 if (!dfn[k]) fa[k]=x,pre[k]=val[i],dfs(k); 35 else if (dfn[k]>dfn[x]){ 36 for (int t=k; t!=x; t=fa[t]) a[++tot]=t,d[t]=1,cf[t]=2,b[tot]=pre[t]; 37 a[++tot]=x; d[x]=1; cf[x]=2; b[tot]=val[i]; 38 } 39 } 40 } 41 42 int main(){ 43 freopen("bzoj2878.in","r",stdin); 44 freopen("bzoj2878.out","w",stdout); 45 scanf("%d%d",&n,&m); 46 rep(i,1,m) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w); 47 rep(i,1,n) cf[i]=1; 48 if (m==n-1){ 49 Dn(1,0); cf[1]=0; 50 For(i,1) fa[k=to[i]]=1,Up(k,val[i]); 51 }else{ 52 dfs(1); 53 rep(i,1,tot) Dn(a[i],0); 54 rep(i,1,tot){ 55 int x=a[i]; double k=0.5; 56 for (int j=i%tot+1; j!=i; j=j%tot+1){ 57 if (j%tot+1!=i) up[x]+=k*(b[F(j)]+dn[a[j]]*son[a[j]]/(son[a[j]]+1)); 58 else up[x]+=k*(b[F(j)]+dn[a[j]]); 59 k/=son[a[j]]+1; 60 } 61 k=0.5; 62 for (int j=F(i); j!=i; j=F(j)){ 63 if (F(j)!=i) up[x]+=k*(b[j]+dn[a[j]]*son[a[j]]/(son[a[j]]+1)); 64 else up[x]+=k*(b[j]+dn[a[j]]); 65 k/=son[a[j]]+1; 66 } 67 } 68 rep(j,1,tot){ 69 int x=a[j]; 70 For(i,x) if (!d[k=to[i]]) fa[k]=x,Up(k,val[i]); 71 } 72 } 73 rep(i,1,n) ans+=(up[i]*cf[i]+dn[i]*son[i])/(cf[i]+son[i]); 74 printf("%.5lf\n",ans/n); 75 return 0; 76 }