HDU 4089 Activation

概率,$dp$。

设$dp[i][j]$表示有$i$个人在排队,$Tomato$排在第$j$个的情况下,到达目标状态的概率。$dp[n][m]$为答案。

当$j=1$时,$dp[i][1]=p1*dp[i][1]+p2*dp[i][i]+p4$;

当$2<=j<=k$时,$dp[i][j]=p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1]+p4$;

当$k<j<=i$时,$dp[i][j]=p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1]$。

将上面三个式子第一项往左移,左右同除以左边系数之后,得到:

当$j=1$时,$dp[i][1]=A*dp[i][i]+C$;

当$2<=j<=k$时,$dp[i][j]=A*dp[i][j-1]+B*dp[i-1][j-1]+C$;

当$k<j<=i$时,$dp[i][j]=A*dp[i][j-1]+B*dp[i-1][j-1]$。

其中$A=p2/(1-p1)$,$B=p3/(1-p1)$,$C=p4/(1-p1)$。

加下来就是要把这个东西算出来。又是一顿骚操作。

再写的简单一点吧:

当$j=1$时,$dp[i][1]=A*dp[i][i]+x[j]$,此时$x[j]=C$;

当$2<=j<=k$时,$dp[i][j]=A*dp[i][j-1]+x[j]$,此时$x[j]=B*dp[i-1][j-1]+C$;

当$k<j<=i$时,$dp[i][j]=A*dp[i][j-1]+x[j]$,此时$x[j]=B*dp[i-1][j-1]$;

$x[j]$可以通过$dp[i-1][....]$直接算出来。

假设现在我们需要计算$dp[4][1]$至$dp[4][4]$,我们分别设$dp[4][1]$至$dp[4][4]$为$a$,$b$,$c$,$d$。

得到四个等式:

$a=A*d+x[1]$ ①

$b=A*a+x[2]$ ②

$c=A*b+x[3]$ ③

$d=A*c+x[4]$ ④

将②代入③,再将新得到的③代入④,再将新得到的④代入①,

得到:$a=A^4*a+A^3*x[2]+A^2*x[3]+A^1*x[4]+A^0*x[1]$ ⑤,就可以求出$a$了,即求出了$dp[4][1]$。

⑤式子的得到是有规律的,自己写一遍就知道了。得到了$dp[4][1]$就可以知道$dp[4][2..4]$了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-6;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar();
    x = 0;
    while(!isdigit(c)) c = getchar();
    while(isdigit(c))
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
}

int n,m,k;
double p1,p2,p3,p4,A,B,C;
double dp[2][2005],x[2005];
double powA[2005];

int main()
{
    while(~scanf("%d%d%d%lf%lf%lf%lf",&n,&m,&k,&p1,&p2,&p3,&p4))
    {
        if(p4<eps)
        {
            printf("0.00000
");
            continue;
        }
        A=p2/(1-p1); B=p3/(1-p1); C=p4/(1-p1);

        powA[0]=1; for(int i=1;i<=n;i++) powA[i]=powA[i-1]*A;

        int flag=0; dp[flag][1]=C/(1-A); flag=1;
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(j==1) x[j]=C;
                else if(j>=2&&j<=k) x[j]=B*dp[flag^1][j-1]+C;
                else x[j]=B*dp[flag^1][j-1];
            }

            double sum=0;
            for(int j=2;j<=i;j++) sum=sum+x[j]*powA[i+1-j];
            sum=sum+x[1]*powA[0];

            dp[flag][1]=sum/(1-powA[i]);

            for(int j=2;j<=i;j++)  dp[flag][j]=A*dp[flag][j-1]+x[j];

            flag=flag^1;

        }
        printf("%.5f
",dp[flag^1][m]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/6307175.html