【BZOJ 3925】【ZJOI 2015】[概率dp]地震後的幻想鄉
阿新 • • 發佈:2019-02-12
題目描述
題目分析
PoPoQQQ大爺的概率DP看不懂,看了另外一個大神的題解…好像跟概率dp沒什麼關係。
根據提示,對於n個[0,1]之間的隨機變數 l,1−Pall,2)+...+m+1m+1×(Pall,m)
把
現在的任務是怎麼計算
對於計算
具體細節可以參考程式碼。
程式碼
/**************************************************************
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));
}