poj2096

收集漏洞

·述题意:

     输入n,s表示这里存在n种漏洞和s个系统(0<n,s<=1000)。工程师可以花费一天去找出一个漏洞——这个漏洞可以是以前出现过的种类,也可能是未曾出现过的种类,同时,这个漏洞出现在每个系统的概率相同。要求得出找到n种漏洞,并且在每个系统中均发现漏洞的期望天数。

·分析:

     这是一道求期望值的题目。题目中的两个关键字提醒我们二维状态设计或许很美妙。根据上题的路子,我们用状态f[i][j]表示已经发现了i种漏洞同时已经有j个系统发现了漏洞的情况下最终达到题目要求(f[n][s])的期望天数。

     进一步。由题目可知,其实每次漏洞有两种情况(发现过的漏洞和新的漏洞),同时这个漏洞所在的系统也有两种情况(之前已经发现漏洞的系统和之前没有发现漏洞的系统),所以组合一下,共有四情况,一起来转移吧:

               image 

       由图,我们可以轻松得到转移方程吗?还差一丢丢。因为目的是求出期望值——什么是期望值?好吧,暂时可以理解为“权值 x 概率”。因此期望Dp的转移是有代价的,而不像概率Dp那样简单统计了。另外一个问题,类似于上文的机器人分身,当前状态的期望值有多个转移方向,所以此处要乘上概率——也就是选择这一步的概率P,如下:

     f[i][j]—>f[i+1][j+1]: P1=(n-i)*(s-j)/n*s

     f[i][j]—>f[i+1][j]   : P2=(n-i)*j    /n*s

     f[i][j]—>f[i][j+1]   : P3=i*(s-j)    /n*s

     f[i][j]—>f[i][j]      : P4=i*j        /n*s

     然后算上转移的代价(1天),我们开始思考最终的DP转移方程式。这里我们将f[n][s]=0定为边界——很合理,表示找到n种漏洞,有s个系统发现漏洞距离目标状态的期望天数(就是一样的状态,所以期望天数是0啊)。据此我们设计出一个逆推的Dp方程式:

                                    f[i][j]=

   (f[i][j]+1)*P4+(f[i][j+1]+1)*P3+(f[i+1][j]+1)*P2+(f[i+1][j+1]+1)*P1

     你会发现方程左右两边都有f[i][j],所以就对式子进行化简。化简如下:

f[i][j]=f[i][j]*P4+f[i][j+1]*P3+f[i+1][j]*P2+f[i+1][j+1]*P1+(P1+P2+P3+P4)

f[i][j]*(1-P4)  = f[i][j+1]*P3+f[i+1][j]*P2+f[i+1][j+1]*P+      1

     最终就是将左边系数除过去然后带入p1p2p3p4,逆推转移就是了,答案当然就在f[0][0]诞生啦,代码也来啦:

#include<stdio.h>
#define ro(i,a,b) for(int i=a;i>=b;i--)
const int N=1003;int n,m;double f[N][N];
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        f[n][m]=0;
        ro(i,n,0)
        ro(j,m,0)if(i!=n||j!=m)
        f[i][j]=
        (
            f[i+1][j]*(n-i)*j+
            f[i][j+1]*i*(m-j)+
            f[i+1][j+1]*(n-i)*(m-j)+n*m
        )/
        (
            n*m-i*j
        );        
        printf("%.4f\n",f[0][0]);
    }
    return 0;
}

 

posted @ 2018-04-25 18:31  lnyzo  阅读(76)  评论(0编辑  收藏  举报