题目描述
题目分析
PoPoQQQ大爷的概率DP看不懂,看了另外一个大神的题解…好像跟概率dp没什么关系。
根据提示,对于n个[0,1]之间的随机变量
x1,x2,...,xm
,第
k
小的那个的期望值是
把
P
提出来就有
现在的任务是怎么计算
P
,我们可以先把不连通的方案数算出来再除以总方案数,设不连通的方案数为
对于计算
具体细节可以参考代码。
代码
/**************************************************************
Problem: 3925
User: bzjudge2
Language: C++
Result: Accepted
Time:104 ms
Memory:2384 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define MAXN 10
#define MAXM 50
#define MAXS 1024
#define INF 0x3f3f3f3f
typedef long long int LL;
template<class T>
void Read(T &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(flag)x=-x;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
int n,m;
int to[MAXN+10];
int cnt[MAXS+100],sz[MAXS+100];
LL f[MAXS+100][MAXM+10];//S中选j条边使得不连通
LL g[MAXS+100][MAXM+10];//S中选j条边使得连通
LL C[MAXM+10][MAXM+10];
void init(){
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
C[0][0]=1;
for(int i=1;i<=MAXM;++i){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;++j)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
int main(){
init();
Read(n),Read(m);
int a,b;
for(int i=1;i<=m;++i){
Read(a),Read(b);
--a,--b;
to[b]|=1<<a;
to[a]|=1<<b;
}
int ed=1<<n;
for(int s=1;s<ed;++s){
sz[s]=sz[s>>1]+(s&1);
if(sz[s]==1){
g[s][0]=1;
continue;
}
for(int i=0;i<n;++i)
if(s&(1<<i))cnt[s]+=sz[to[i]&s];//i点可以到达的s内点的边数
cnt[s]>>=1;
int lowbit=s&-s;//任选一点
for(int t=s&(s-1);t>0;t=(t-1)&s)//枚举每一中包含lowbit的s子集
if(t&lowbit){
for(int i=0;i<=cnt[t];++i)//t中选择的边数
for(int j=0;j<=cnt[s^t];++j)//s-t中选择的边数
f[s][i+j]+=g[t][i]*C[cnt[s^t]][j];//保证不选择s~t的边
}
for(int i=0;i<=cnt[s];++i)
g[s][i]=C[cnt[s]][i]-f[s][i];
}
double ans=0;
for(int i=0;i<=m;++i)
ans+=(double)f[ed-1][i]/C[cnt[ed-1]][i];
printf("%0.6lf\n",ans/(m+1));
}