給定一個\(n\)個節點\(m\)條邊的無向圖,其中每條邊的權值在\([0,1]\)內均勻隨機,
求最小生成樹最大邊權的指望。
\(n\le 10,m\le \frac{n(n-1)}{2}\)c++
這題有兩種作法。函數
因爲邊權的指望
\[ \begin{aligned} E(X)&=\int_0^1P(X=x)xdx\\ &=\int_0^1P(X=x)\int_0^xdtdx\\ &=\int_0^1(\int_t^1P(X=x)dx)dt\\ &=\int_0^1P(X\ge t)dt\\ \end{aligned} \]故考慮邊權的機率生成函數\(F(x)=\int_0^1P(x\ge t)dt\)。spa
設\(P_S(t)\)爲\(S\)內的節點經過\(<t\)的邊不能連通的機率,經過子集容斥可得轉移方程爲
\[\int_0^1P_S(t)dt=\int_0^1\sum_{S_0\subsetneq S,p\in S_0}(1-t)^{T(S_0,S-S_0)}(1-P_{S_0}(t))dt\]其中\(p\)爲點集\(S\)內肯定的一點。
轉化得
\[ \begin{aligned} \int_0^1P_S(t)dt&=\int_0^1\sum_{S_0\subsetneq S,p\in S_0}(1-t)^{T(S_0,S-S_0)}(1-P_{S_0}(t))dt\\ &=\sum_{S_0\subsetneq S,p\in S_0}\int_0^1(1-t)^{T(S_0,S-S_0)}(1-P_{S_0}(t))dt\\ &=\sum_{S_0\subsetneq S,p\in S_0}\int_0^1(1-t)^{T(S_0,S-S_0)}-(1-t)^{T(S_0,S-S_0)}P_{S_0}(t)dt\\ &=\sum_{S_0\subsetneq S,p\in S_0}\frac{1}{1+T(S_0,S-S_0)}-\int_0^1(1-t)^{T(S_0,S-S_0)}P_{S_0}(t)dt\\ \end{aligned} \]
因而有
\[\int_0^1(1-t)^kP_S(t)dt=\sum_{S_0\subsetneq S,p\in S_0}\frac{1}{1+k+T(S_0,S-S_0)}-\int_0^1(1-t)^{k+T(S_0,S-S_0)}P_{S_0}(t)dt\]code
記錄\(S,k\),直接一路推到答案便可。ip
首先若是咱們枚舉\(m\)條邊的大小關係(\(O(m!)\)種)很顯然這\(m!\)中關係出現的機率都是相等的
那麼咱們就有了一個\(O(mm!)\)的暴力作法:
知道了邊的大小關係,咱們就能夠知道最小生成樹的最大邊的排名了,而後直接套用給出的公式便可get
如今考慮子集dp,設\(f[S][k]\)表示在點集\(S\)內最小生成樹的最大邊排名爲\(k\)的機率it
發現這個無法轉移,考慮將這個條件轉化爲在S內連了k條邊後連通的方案數
轉移有\[f[S][k]=\binom{A[S]}{k}-\sum_{S_0\subsetneq S,p\in S_0}\sum_{i=0}^kf[S_0][i]\binom{A[S-S_0]}{k-i}\]其中\(A[S]\)表示\(S\)內的邊數。io
但咱們發現求出來\(WA\)了。
從新考慮一下,在S內連了k條邊後連通的方案數應該是點集\(S\)內最小生成樹的最大邊排名小於等於\(k\)的機率class
因此利用以前的公式,\(E=\sum_{i=1}^{m}P(x=i)i=\sum_{i=1}^{m}P(x\ge i)=\sum_{i=1}^{m}1-P(x\le i-1)\)file
而後就能夠作了。
#include<bits/stdc++.h> #define FL "a" using namespace std; typedef long long ll; typedef double dd; const int N=52; const int mod=997; const dd eps=1e-9; inline ll read(){ ll data=0,w=1;char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar(); return data*w; } inline void file(){ freopen(FL".in","r",stdin); freopen(FL".out","w",stdout); } int n,m,A[1<<10],cnt[1<<10],low[1<<10]; dd c[N][N],ans,dp[1<<10][N]; void print(int s,int k){if(k)print(s>>1,k-1),putchar(48+(s&1));} dd dfs(int s,int k){ if(dp[s][k]>=0)return dp[s][k]; if(cnt[s]==1&&!k)return 1;if(A[s]<k)return 0; dd &res=dp[s][k];res=c[A[s]][k]; for(int i=k;~i;i--) for(int t=(s-1)&s;t;t=(t-1)&s) if(t&1<<low[s])res-=dfs(t,i)*c[A[s^t]][k-i]; return res; } int main() { n=read();m=read(); for(int i=1,u,v;i<=m;i++){ u=read()-1;v=read()-1; for(int s=0;s<(1<<n);s++) if((s&(1<<u|1<<v))==(1<<u|1<<v))A[s]++; } for(int s=0;s<(1<<n);s++) cnt[s]=cnt[s>>1]+(s&1),low[s]=(s&1)?0:low[s>>1]+1; for(int s=0;s<(1<<n);s++) for(int i=0;i<=m;i++)dp[s][i]=-1; for(int i=0;i<=m;i++) for(int j=c[i][0]=1;j<=i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1]; for(int i=1;i<=m+1;i++)ans+=1.0-dfs((1<<n)-1,i-1)/c[m][i-1]; printf("%.6lf\n",ans/(m+1)); return 0; }