【动态规划】随机图

来源:互联网 发布:淘宝小号批发哪里靠谱 编辑:程序博客网 时间:2024/04/28 18:54

题目描述

  随机生成一张n个点的无向图。把他顶点标号为1~n。对于一个点对i,j(1 <= i < j <= n),他有千分之p的概率成为这张图中的一条边(i,j)。不同的边出现的概率是相互独立的。那么生一个至少含有一个大于等于4的连通块的图的概率是多少?

分析

贼难,不想分析

解法一:正难则反,对症下药

正难则反
   存在一个大于等于4的连通块的概率,等价于:1减去所有连通块都小于等于3的概率。 
   状态函数:
   f(i,j,k)表示i个点的图中,有大小为2的连通块j个,大小为3的连通块k个,大小为1的联通块有i-2*j-3*k个的概率。
   边界:
   f(0,0,0)=1;
   转移方程:
   刷表法——分析在f(i,j,k)的基础上新加入1个点的状态转移:
   情况1、若新点与前面i个点中任何一个都不连边,则状态转移成 f(i+1,j,k)+=f(i,j,k)*(1-p)^i
   情况2、若新点与前面i个点中任意一个大小为1的连通块 连一条边构成一个大小为2的连同块,则状态转移成:f(i+1,j+1,k)+=f(i,j,k)*(i-2*j-3*k)*p*(1-p)^(i-1)
   情况3、若新点与前面i个点中任意 两个 大小为1的连通块连一条边构成一个大小为3的连同块,则状态转移成:f(i+1,j,k+1)+=f(i,j,k)*C(i-2*j-3*k,2)*p*p*(1-p)^(i-2)
   情况4、若新点与前面i个点中任意一个大小为2的连通块连一条边构成一个大小为3的连同块,则状态转移成:f(i+1,j-1,k+1)+=f(i,j,k)*2*j*p*(1-p)^(i-1)
   情况5、若新点与前面i个点中任意一个大小为2的连通块连两条边构成一个大小为3的连同块(大小为2的连通块的两个点分别连一条边),则状态转移成:f(i+1,j-1,k+1)+=f(i,j,k)*j*p*(1-p)^(i-1)

   对不起我抄题解了

解法二:正难则反+大佬就是不一样——%%%通解通法

借鉴了某位超级大犇的算法,强的一p。

f(i)表示i个结点能够连通的概率

g(i)表示i个结点无法满足至少有一个连通块大于等于4的概率

正难则反:先考虑加入结点不能使图连通。对于新加入的结点,分析:

若它和已有的i-1个结点形成了一块大小为j的连通块,相当于从i-1个结点中选择j-1个出来和现在的这个结点形成连通块,那么形成的概率为f(j)*C(i-1,j-1) 

要使这个连通块不连通,则剩下的i-j个结点和这个连通块里面的所有节点都不能连通,概率为((1-p)^(i-j))^j=(1-p)^(j*(i-j))

所以说此时形成大小为j的连通块并且这i个结点不连通的概率:f(j)*C(i-1,j-1)*(1-p)^(j*(i-j)) 

g(i)类似,在这j个结点不与外界连通的同时,剩下的i-j个结点的大小也不能大于等于4,所以概率为:f(j)*C(i-1,j-1)*(1-p)^(j*(i-j))*g(i-j)

综上,f(i)=1-sum{f(j)*C(i-1,j-1)*(1-p)^(j*(i-j)) | 1<=j<i}

g(i)=sum{f(j)*C(i-1,j-1)*(1-p)^(j*(i-j))*g(i-j) | 1<=j<=3}

当然,i<=3时,就算这i个结点全部连通,都无法满足至少有一个连通块大于等于4,所以说此时g(i)+=f(i)

但是当j*(i-j)很大的时候,(1-p)^(j*(i-j))会趋近于0,题目精度要求不高,取对数避免

最终答案ans=1-g(n) 

贴一下算法二的代码

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<cctype>#include<cstdlib>#include<algorithm>#include<vector>#include<stack>#include<queue>#include<set>#include<map>using namespace std;const int maxn=105,maxm=10005;int n;double p;void workin(){scanf("%d%lf",&n,&p);p/=1000;return;}double C[maxn][maxn],fact[maxn],epow[maxm];void ready(){epow[0]=0;for(int i=1;i<=10000;i++){epow[i]=epow[i-1]+log(1-p);}fact[0]=fact[1]=0;for(int i=2;i<=n;i++){fact[i]=fact[i-1]+log(i);}for(int i=1;i<=n;i++){for(int j=0;j<=i;j++){C[i][j]=fact[i]-fact[j]-fact[i-j];}}return;}double d[maxn],f[maxn];void dp(){d[1]=f[1]=0;for(int i=2;i<=n;i++){double sum=0;for(int j=1;j<i;j++){sum+=exp(d[j]+C[i-1][j-1]+epow[j*(i-j)]);}d[i]=log(1-sum);sum=0;for(int j=1;j<i && j<=3;j++){sum+=exp(d[j]+C[i-1][j-1]+epow[j*(i-j)]+f[i-j]);}f[i]=log(sum);if(i<4){f[i]=log(exp(f[i])+exp(d[i]));}}return;}void solve(){ready();dp();printf("%.4lf",1-exp(f[n]));return;}int main(){freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);workin();solve();return 0;}
最后说一句,fuse123fuseTQL!!!!

原创粉丝点击