題解-ZJOI2015地震後的幻想鄉
阿新 • • 發佈:2018-10-02
最小生成樹 typename ons bit spl 可能 簡述 連續 ++i ;若期望第\(i‘\)次連通整張圖,則答案為\(\frac {i‘}{m+1}\)
Problem
bzoj & 洛谷
題意簡述:給定一個\(n\)(\(n\leq 10\))個點\(m\)條邊的無向圖,每條邊的權值為一個\(0\)到\(1\)之間的連續隨機變量,求圖的最小生成樹中最大邊的期望權值
Solution
\(m\)個範圍\([0,1]\)之間的隨機變量中,第\(i\)大的值期望為\(\frac i{m+1}\)(這個式子我只會證最大值期望為\(\frac m{m+1}\),但不會證第\(i\)大的期望,如果有哪位神犇會證,請賜教)
有了這個東西,再考慮到原題是要求聯通即可,發現\(kruskal\)算法正好符合
將邊排序後加入,若加入到第\(i\)條邊時整張圖連通,則答案為\(\frac i{m+1}\)
設\(f[S][i]\)表示用了\(i\)條邊不能使\(S\)聯通的方案數,\(g[S][i]\)表示用了\(i\)條邊能使\(S\)聯通的方案數,\(C[S]\)表示點集\(S\)內部道路數量
\[f[S][j]=\sum g[s][i]\cdot \binom {C[S-s]}{j-i}\]
\[g[S][j]=\binom {C[S]}i-f[S][j]\]
考慮到若第\(i\)條邊加入後仍未連通,則會對後面都造成影響(類似整數期望公式的一種統計方法)
\[Ans=\frac 1{m+1}\sum_{i=0}^m\frac {f[A][i]}{\binom {C[A]}{i}}\]
最後記得在枚舉集合的時候要定下一個點強制選擇,否則可能會拓撲序紊亂(代碼裏的做法就是\(S+=2\)而不是\(++S\),這樣枚舉的集合必定含有\(1\)號節點)
Code
#include <bits/stdc++.h> typedef long long ll; #define rg register template <typename _Tp> inline _Tp read(_Tp&x){ char c11=getchar(),ob=0;x=0; while(c11^‘-‘&&!isdigit(c11))c11=getchar();if(c11==‘-‘)ob=1,c11=getchar(); while(isdigit(c11))x=x*10+c11-‘0‘,c11=getchar();if(ob)x=-x;return x; } const int N=11,M=60,MS=1<<N; ll c[M][M],C[MS],f[MS][M],g[MS][M]; int n,m,A,bin[N]; void init();void work();void print(); int main(){init();work();print();return 0;} void work(){ for(rg int S=1;S<bin[n];S+=2) for(rg int j=0;j<=C[A];++j){ for(rg int s=(S-1)&S;s;s=(s-1)&S) for(rg int i=0;i<=j;++i) f[S][j]+=g[s][i]*c[C[S-s]][j-i]; g[S][j]=c[C[S]][j]-f[S][j]; } } void print(){ double ans(0.0); for(rg int i=0;i<=C[A];++i) ans+=1.0*f[A][i]/c[C[A]][i]; printf("%.6lf\n",ans/(C[A]+1)); } void init(){ read(n),read(m);A=(1<<n)-1; int x,y;bin[0]=1; for(rg int i=1;i<=n;++i)bin[i]=bin[i-1]<<1; for(rg int i=0;i<=m;++i){ c[i][0]=1; for(int j=1;j<=i;++j) c[i][j]=c[i-1][j-1]+c[i-1][j]; } while(m--){ read(x),read(y);--x,--y; for(rg int S=1;S<bin[n];++S) if( S&bin[x] and S&bin[y] ) ++C[S]; } }
題解-ZJOI2015地震後的幻想鄉