【NOI2012】迷失游乐园
作者:互联网
题目链接:迷失游乐园(BZOJ) 迷失游乐园(Luogu)
独立完成的题,写一发题解纪念一波~
模拟完样例大概可以知道是道树形DP了。
观察数据范围,发现是基环树,至少会有一个环。
先从树的部分开始考虑,如果没有环,怎么DP呢?
先选取一个点为根,f[i]表示从i节点出发走到其子树的路径期望长度。
那么f[x]= sum(f[son]+w[i])/(rd[x]-1),w[i]为son到x的边长,rd[x]为x的度数,当然如果到了根节点,就不必要减1。
然后再换根一波,统计答案就可以了。换根时注意节点度数的处理就行。
这样就能轻松拿到50分的良心部分分。
如果是基环树呢?
习惯把基环树看成一个“细菌”,把环放正中间考虑。
每一个在环上的点都连接着一个子树,先用前面树形DP的方法对每部分子树进行求解,先不换根。
对于环上每个点,可以逆时针走,也可以顺时针走,所以枚举它左右两条边断掉,拆成链。
在链上推一遍就可以得到从这个点往右或往左走的路径期望长。(环上点数量很少,复杂度在允许的范围内)
用这两种期望长度再去更新这个点,然后跑到这个点对应的子树去换根、统计答案。
算期望除以点度数时比较繁琐,写的时候要小心。
代码~
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 #define For(i,a,b) for(register int i=a;i<=b;++i) 8 #define Dwn(i,a,b) for(register int i=a;i>=b;--i) 9 #define Re register 10 #define Db double 11 12 using namespace std; 13 14 const int N=1e5+5; 15 16 int head[N],nxt[N*2],v[N*2],cnt=1; 17 Db f[N],w[N*2],rd[N],z,ans=0,Dn; 18 int n,x,y,m; 19 bool Fcr[N],vis[N],Ffd=0; 20 21 inline void read(int &v){ 22 v=0; 23 char c=getchar(); 24 while(c<'0'||c>'9')c=getchar(); 25 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar(); 26 } 27 inline void read(Db &v){ 28 v=0; 29 char c=getchar(); 30 while(c<'0'||c>'9')c=getchar(); 31 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar(); 32 } 33 void add(int ux,int vx,Db wx){ 34 cnt++; rd[ux]+=1; 35 nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx; 36 cnt++; rd[vx]+=1; 37 nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx; 38 } 39 void dfsDP(int x,int fa){ 40 for(Re int i=head[x];i;i=nxt[i]){ 41 int vv=v[i]; if(vv==fa)continue; 42 if(Fcr[vv])continue; 43 dfsDP(vv,x); 44 f[x]+=f[vv]+w[i]; 45 } 46 if(rd[x]>1&&fa)f[x]/=(rd[x]-1.0); 47 if(fa==0&&rd[x])f[x]/=rd[x]; 48 } 49 void dfsFA(int x,int fa){ 50 ans+=f[x]/Dn; 51 for(Re int i=head[x];i;i=nxt[i]){ 52 int vv=v[i]; if(vv==fa)continue; 53 if(Fcr[vv])continue; 54 Db Bfx=f[x]; Db Bfv=f[vv]; 55 56 Bfx=f[x]*rd[x]-f[vv]-w[i]; 57 if(rd[x]>1)Bfx/=(rd[x]-1); 58 59 f[vv]=f[vv]*(rd[vv]-1)+Bfx+w[i]; 60 f[vv]/=rd[vv]; 61 dfsFA(vv,x); 62 f[vv]=Bfv; 63 } 64 } 65 int st[N],top=0,tot=-1,cr[N][2]; 66 Db dsf[N],dcr[N][2],fx[N][2]; 67 void dfsCIR(int x,int fa){ 68 vis[x]=1; st[++top]=x; 69 for(Re int i=head[x];i;i=nxt[i]){ 70 int vv=v[i]; if(vv==fa)continue; 71 if(vis[vv]){ 72 Ffd=1; 73 while(st[top]!=vv){ 74 int stx=st[top--]; 75 cr[++tot][0]=stx; dcr[tot][0]=dsf[stx]; Fcr[stx]=1; 76 } 77 cr[++tot][0]=vv; dcr[tot][0]=w[i]; Fcr[vv]=1; 78 return; 79 } 80 dsf[vv]=w[i]; 81 dfsCIR(vv,x); 82 if(Ffd)return; 83 } 84 top--; 85 } 86 void getF12(int pos,int now){ 87 int p=pos+1; 88 Db Fx=0; 89 if(p>tot)p=0; 90 Fx=f[cr[p][now]]; 91 do{ 92 Fx+=dcr[p][now]; 93 p++; if(p>tot)p=0; 94 if(p==pos)break; 95 int cx=cr[p][now]; 96 Db Fcx=f[cx]*(rd[cx]-2); 97 Fx=(Fx+Fcx)/(rd[cx]-1); 98 }while(p!=pos); 99 fx[ cr[pos][now] ][now]=Fx; 100 } 101 102 int main(){ 103 read(n); read(m); Dn=n; 104 memset(Fcr,0,sizeof(Fcr)); 105 memset(vis,0,sizeof(vis)); 106 For(i,1,m){ 107 read(x); read(y); read(z); 108 add(x,y,z); 109 } 110 if(m<n){ 111 dfsDP(1,0); dfsFA(1,0); 112 printf("%.05lf",ans); 113 return 0; 114 } 115 dfsCIR(1,0); 116 For(i,0,tot){ 117 rd[cr[i][0]]-=2; 118 dfsDP(cr[i][0],0); 119 rd[cr[i][0]]+=2; 120 } 121 For(i,0,tot){ 122 cr[i][1]=cr[tot-i][0]; 123 if(i!=tot)dcr[i][1]=dcr[tot-i-1][0]; 124 else dcr[i][1]=dcr[tot][0]; 125 } 126 127 For(i,0,tot){ 128 getF12(i,0); getF12(i,1); 129 } 130 For(i,0,tot){ 131 int cx=cr[i][0]; 132 f[cx]*=(rd[cx]-2); 133 f[cx]+=fx[cx][0]+fx[cx][1]; 134 f[cx]/=rd[cx]; 135 dfsFA(cx,0); 136 } 137 printf("%.05lf",ans); 138 return 0; 139 }
标签:NOI2012,游乐园,int,Db,vv,tot,rd,迷失,now 来源: https://www.cnblogs.com/HLAUV/p/10358058.html