概率dp学习笔记+概率dp题

总结的规律:

1.期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+…) = aE(A) + bE(B) +…+1;
2.期望从后往前找,一般dp[n]=0,dp[0]是答案;
3.解决过程,找出各种情况乘上这种情况发生的概率,求和;


【1】A - Collecting Bugs
我是题目链接

题意:一个软件有s个子系统,会产生n种bug。
某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中。
求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
需要注意的是:bug的数量是无穷大的,所以发现一个bug,出现在某个子系统的概率是1/s,
属于某种类型的概率是1/n。
解法:
dp[i][j]表示已经找到i种bug,并存在于j个子系统中,要达到目标状态的天数的期望。
显然,dp[n][s]=0,因为已经达到目标了。而dp[0][0]就是我们要求的答案。
dp[i][j]状态可以转化成以下四种:
dp[i][j] 发现一个bug属于已经找到的i种bug和j个子系统中
dp[i+1][j] 发现一个bug属于新的一种bug,但属于已经找到的j种子系统
dp[i][j+1] 发现一个bug属于已经找到的i种bug,但属于新的子系统
dp[i+1][j+1]发现一个bug属于新的一种bug和新的一个子系统
以上四种的概率分别为:
p1 = i*j / (n*s)
p2 = (n-i)*j / (n*s)
p3 = i*(s-j) / (n*s)
p4 = (n-i)*(s-j) / (n*s)
又有:期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+…) = aE(A) + bE(B) +…
所以:
dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1;
整理得:
dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 )
= ( n*s + (n-i)j*dp[i+1,j] + i(s-j)dp[i,j+1] + (n-i)(s-j)*dp[i+1,j+1] )/( n*s - i*j )

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
double dp[1010][1010];
int n,s;
int main()
{
    while(~scanf("%d%d",&n,&s))
    {
        dp[n][s] = 0;
        for(int i = n; i >= 0; i --)
        {
            for(int j = s; j >= 0; j --)
            {
                if(i == n && j == s) continue;
                int p1 = (n - i) * (s - j) * 1.0;
                int p2 = (n - i) * j * 1.0;
                int p3 =  i * (s - j) * 1.0;
                int p4 = i * j * 1.0;
                dp[i][j] = (p1 * dp[i+1][j+1] + p2 * dp[i+1][j] + p3 * dp[i][j+1] + n*s) / (n * s - p4);
            }
        }
        printf("%.4lf\n",dp[0][0]);
    }
}

【2】B - Aeroplane chess
我是题目链接
思考:一个6个面的骰子,很快我就会做到一个有m面的骰子。。。。。这里还有一个知识点,就是可以直接从一个点到另一个点,不需要扔骰子,那么dp[i]=dp[go[i]];
题意:
有编号为0-n的格子,从0开始,扔骰子扔到几就走几格。有m个瞬移点,每个点可以从格x直接飞到格y,若瞬移到另一个瞬移点可以继续瞬移。求到达格n的期望扔骰子次数。
思路:
E(i)——到格i期望,E(i)=i是某个瞬移目标点?(E(x),x指瞬移出发点),否则E(i+1)*1/6+E(i+2)*1/6+…+E(i+6)*1/6+1,注意最后把“又走了一步”加上。标准全期望公式。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int go[100005];
double dp[100005];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
        {
            break;
        }
        else
        {
            memset(go,-1,sizeof(go));
            for(int i=1; i<=m; i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                go[x]=y;
            }
           memset(dp,0,sizeof(dp));
            for(int i=n-1; i>=0; i--)
            {
                if(go[i]!=-1)
                {
                    dp[i]=dp[go[i]];
                }
                else
                {
                    dp[i]=dp[i+1]/6.0+dp[i+2]/6.0+dp[i+3]/6.0+dp[i+4]/6.0+dp[i+5]/6.0+dp[i+6]/6.0+1.0;
                }
            }
            printf("%.4f\n",dp[0]);
        }

    }
}

【3】F - Dice
我是题目链接
题意:
扔一个有m个面的骰子,每个面有一个数字,这些数字互不相同,求连续扔到n个数相同的期望步数或连续扔到n个数不同的期望步数。
思路:
下面的三个图片:不想自己打了:
这里写图片描述

这里写图片描述

这里写图片描述
思考:
一开始没推出来dp[0]的直接结果,推出来dp[i],dp[i+1],dp[i+2]之间差的等比关系了;
本来想直接写,写的时候发现,dp[1]一开始不是已知的;然后就不能直接写了,还是得推出最后的dp[0],dp[n]的那个式子;好在把dp[0]-dp[1]=1弄明白后其他的就好推出了;
代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double qiu0(int m,int n)
{
    return (pow(m,n)-1.0)/(m-1.0);
}
double qiu1(int m,int n)
{
    double ans=1;
    double p=1.0;
    for(int i=1; i<n; i++)
    {
        p=(m*1.0)/((m-i)*1.0)*p;
        ans+=p;
    }
    return ans;
}
int main()
{
    int t;
    while(~scanf("%d",&t))
    {
        for(int i=1; i<=t; i++)
        {
            int p,m,n;
            scanf("%d%d%d",&p,&m,&n);
            if(p==0)
            {
                printf("%.9f\n",qiu0(m,n));
            }
            else
            {
                printf("%.9f\n",qiu1(m,n));

            }
        }
    }
}

【4】SPOJ Favorite Dice(数学期望)
无题目链接;
BuggyD loves to carry his favorite die around. Perhaps you wonder why it’s his favorite? Well, his die is magical and can be transformed into an N-sided unbiased die with the push of a button. Now BuggyD wants to learn more about his die, so he raises a question:

What is the expected number of throws of his die while it has N sides so that each number is rolled at least once?

Input

The first line of the input contains an integer t, the number of test cases. t test cases follow.

Each test case consists of a single line containing a single integer N (1 <= N <= 1000) - the number of sides on BuggyD’s die.

Output

For each test case, print one line containing the expected number of times BuggyD needs to throw his N-sided die so that each number appears at least once. The expected number must be accurate to 2 decimal digits.

Example

Input:
2
1
12

Output:
1.00
37.24

题意:
甩一个n面的骰子,问每一面都被甩到的次数期望是多少。
思路:
比较简单,公式:初始化dp[]=0; dp[i]=i/n*dp[i]+(n-i)/n*dp[i+1]+1; 化简逆推即可。 求的是dp[0];
思考:这个题的思路跟第一个题很像了;
代码:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<memory>
using namespace std;
double dp[2000];
int main()
{
    int T,i,j,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n); dp[n]=0;
        for(i=n-1;i>=0;i--) dp[i]=(dp[i+1]*(n-i)/n+1)*n/(n-i);
        printf("%.2lf\n",dp[0]);
    } return 0;
}

【5】E - Crossing Rivers
我是很慢的题目链接

题目大意:

有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v。船会往返在河的两岸,人到达河岸时,船的位置是随机的(往返中)。问说人达到公司所需要的期望时间。

思路:

过每条河最坏的情况是t=3*L/v; 即去的时候船刚刚走。

过没条河最优的情况是t=L/v; 即去的时候船刚刚来。

由于船是均匀发布的,符合线性性质,所以平均下来,过每条河的时间t=2*L/v。
思考:
说实话这个题我有点蒙,这么简单就可以求了么,而且p完全没用上啊;

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int main()
{
    int m,d;
    int q=0;
    while(~scanf("%d%d",&m,&d)&&(m||d))
    {
        q++;
        double ans=0;
        int p,l,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&l,&v);
            ans+=(2.0*l)/(v*1.0);
            d=d-l;
        }
        ans+=d*1.0;
        printf("Case %d: %.3f\n\n",q,ans);
    }

}

先做了5个,其他的在总结
【6】https://www.cnblogs.com/kuangbin/archive/2012/10/04/2711437.html

猜你喜欢

转载自blog.csdn.net/wuxiaowu547/article/details/81835800