zoukankan      html  css  js  c++  java
  • POJ 2096 (概率DP)

    题目链接http://poj.org/problem?id=2096

    题目大意:n种bug,s个子系统。每天随机找一个bug,种类随机,来自系统随机。问找齐n种bug,且每个子系统至少有一个bug的期望天数。

    解题思路

    - -。题目像一坨屎。

    其中"且每个子系统至少有一个bug"比较坑爹,其实意思就是找出s个bug就行了。

    dp[i][j]表示已找到i种bug,且j个系统有bug的期望。

    它可以由四个状态推到:

    ①dp[i][j], 当前找的bug,种类重复,且系统重复。概率为(i/n)*(j/s)。

    ②dp[i][j-1],当前找的bug,种类重复,且系统不重复。概率(i/n)*(s-j)/s。

    ③dp[i-1][j],当前找的bug,种类不重复,且系统重复。概率(n-i)/n*(j/s)。

    ④dp[i-1][j-1],当前找的bug,种类不重复,且系统不重复。概率为(n-i)/n*(s-j)/s。

    最后dp[i][j]+=1.

    由于是求期望,所以要逆推,dp[n][s]=0, ans=dp[0][0] 。

    dp方程的减号全部改为加号。累加然后你会WA掉。因为double精度丢失太严重了。

    dp[i][j]*(i/n)*(j/s)。几次乘几次除,精度会爆。

    所以有必要进行化简, 把乘法化在一起,除法化在一起,最后做一步除法。

    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 )

    由于POJ数据略水,其实化简到第一步就能A。

    #include "cstdio"
    #include "cstring"
    double dp[1005][1005];
    int main()
    {
        int n,s;
        while(scanf("%d%d",&n,&s)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            for(int i=n;i>=0;i--)
            {
                for(int j=s;j>=0;j--)
                {
                    if(i==n&&j==s) continue;
                    double p2=(double(s-j)*i)/n/s;
                    double p3=(double(n-i)*j)/n/s;
                    double p4=(double(n-i)*(s-j))/n/s;
                    double p1=1.0-(double(i*j))/n/s;
                    dp[i][j]=p2*dp[i][j+1]+p3*dp[i+1][j]+p4*dp[i+1][j+1]+1;
                    dp[i][j]/=p1;
                }
            }
            printf("%.4lf
    ",dp[0][0]);
        }
    }
    13634810 neopenx 2096 Accepted 8056K 719MS C++ 679B 2014-11-16 16:08:41

     

     

  • 相关阅读:
    vgcreate语法
    lsmod语法
    lvm语法2
    lvm语法
    mount语法
    fdisk语法
    mdadm语法
    ln语法
    mknod语法
    黑客常用dos-cmd命令
  • 原文地址:https://www.cnblogs.com/neopenx/p/4101521.html
Copyright © 2011-2022 走看看