【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分的良心部分分。

如果是基环树呢?

习惯把基环树看成一个“细菌”,把环放正中间考虑。

【NOI2012】迷失游乐园

每一个在环上的点都连接着一个子树,先用前面树形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 }

 

上一篇:题解 P2081 【[NOI2012]迷失游乐园】


下一篇:[NOI2012]骑行川藏