poj3557 一个很巧妙的概率dp

题目大意很简单,但是做起来实在很难。

最开始看到N很小,想到的是状压dp,dp[i][st]表示考虑前i个点连出去的所有边,st是状态,如果某个点和1点连通,则此位为1

然后转移就枚举i点往连的所有边的可能性...

这样做复杂度为N*2^N*2^N...明显过不了


然后实在想不出看了别人的做法,居然是N^2的!!

别人的解释看得不怎么懂,自己YY了一个解释:

dp[i]表示i个点连通的概率。

直接算dp[i]实在太困难,那么我们算i个点不连通的概率。

先选定一个点p,从这个点出发来看,这个图不连通,则说明图上存在点不和p连通。

设和p连通的点有j个,那么这个图上有C(i-1,j-1)种和有j个点p连通的情况(从剩下的i-1个点中选j-1个点与p连通),每一种情况都有dp[j]的可能连通。

然后就要算这j个点与剩下的i-j个点都不连通的概率了(如果这j个点与剩下的任何1个点连通的话,这个情况就在j+1的时候考虑):(1-p)^(j*(i-j)),乘起来累加就是存在点和p不连通的概率,非p就是不存在点和p不连通,就是所有点都和p连通的概率了~


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=22;
int N;double p;
double dp[maxn];
double pp[maxn*maxn];
int C[maxn][maxn];

void pre()
{
    for(int i=1;i<maxn;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++)
        {
            C[i][j]=C[i][j-1]*(i-j+1)/j;
        }
    }
}

void cal()
{
    pp[0]=1;
    for(int i=1;i<N*N;i++)
        pp[i]=pp[i-1]*(1-p);
}

int main()
{
  //  freopen("in.txt","r",stdin);
    pre();
    while(~scanf("%d%lf",&N,&p))
    {
        cal();
        dp[1]=1;
        for(int i=2;i<=N;i++)
        {
            dp[i]=0;
            for(int j=1;j<i;j++)
            {
                dp[i]+=C[i-1][j-1]*dp[j]*pp[j*(i-j)];
            }
            dp[i]=1-dp[i];
        }
        printf("%.5f\n",dp[N]);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值