概率dp

自不量力开始概率dp

spoj favorite dice //倒推

题意:
一个骰子,n面,求每一面都被扔到至少一次的期望扔的次数。

思路:
d p [ i ] : 已 经 扔 到 i 面 的 期 望 次 数 dp[i]:已经扔到i面的期望次数 dp[i]i
d p [ i ] = d p [ i − 1 ] ∗ n − i + 1 n + d p [ i ] ∗ i n + 1 dp[i]=dp[i-1]*\frac{n-i+1}{n}+dp[i]*\frac{i}{n}+1 dp[i]=dp[i1]nni+1+dp[i]ni+1
移向得: d p [ i ] = d p [ i − 1 ] + n n − i + 1 dp[i]=dp[i-1]+\frac{n}{n-i+1} dp[i]=dp[i1]+ni+1n
f ( 当 前 状 态 的 期 望 ) = ∑ ( f ( 能 转 移 过 来 的 状 态 的 期 望 ) ∗ 概 率 ) + 代 价 f(当前状态的期望)=\sum (f(能转移过来的状态的期望)*概率)+代价 f()=(f())+

/*   Author : Rshs
 *   Data : 2019-09-11-21.13
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const LL mod = 1e9+7;
const int MX = 1e6+5;
double dp[MX];
void Main(int avg){
    int n;cin>>n;
    dp[0]=0;
    for(int i=1;i<=n;i++) dp[i]=dp[i-1]+(1.0*n)/(1.0*n-1.0*i+1.0);
    cout<<dp[n]<<'\n';
}
int main(){
    int cas;cin>>cas;for(int i=1;i<=cas;i++)Main(i);
    return 0;
}

LOOPS //二维倒推

题目

题意:
一个人从(1,1)走到(n,m),当他在(i,j)时,可以花费2魔力施法,有p1几率原地不动,p2几率向右走,p3几率向下走。求到(n,m)的期望花费的魔力。
思路:

正 着 不 好 推 , 考 虑 倒 推 正着不好推,考虑倒推
d p [ i ] [ j ] : 从 ( i , j ) 到 ( n , m ) 的 期 望 , d p [ n ] [ m ] = 0 dp[i][j]:从(i,j)到(n,m)的期望,dp[n][m]=0 dp[i][j]:(i,j)(n,m)dp[n][m]=0
d p [ i ] [ j ] = 2 + d p [ i ] [ j ] ∗ p 1 [ i ] [ j ] + d p [ i + 1 ] [ j ] ∗ p 2 [ i ] [ j ] + d p [ i ] [ j + 1 ] ∗ p 3 [ i ] [ j ] dp[i][j]=2+dp[i][j]*p1[i][j]+dp[i+1][j]*p2[i][j]+dp[i][j+1]*p3[i][j] dp[i][j]=2+dp[i][j]p1[i][j]+dp[i+1][j]p2[i][j]+dp[i][j+1]p3[i][j]
移 向 得 : d p [ i ] [ j ] = ( 2 + d p [ i + 1 ] [ j ] ∗ p 2 [ i ] [ j ] + d p [ i ] [ j + 1 ] ∗ p 3 [ i ] [ j ] ) / ( 1 − p 1 [ i ] [ j ] ) 移向得:dp[i][j]=(2+dp[i+1][j]*p2[i][j]+dp[i][j+1]*p3[i][j])/(1-p1[i][j]) dp[i][j]=(2+dp[i+1][j]p2[i][j]+dp[i][j+1]p3[i][j])/(1p1[i][j])
这 里 注 意 p 1 [ i ] [ j ] = = 1 时 候 , 直 接 c o n t i n u e . 这里注意p1[i][j]==1时候,直接continue. p1[i][j]==1,continue. 保 证 有 解 , 说 明 走 到 这 种 点 的 概 率 为 0 保证有解,说明走到这种点的概率为0 ,0

/*   Author : Rshs
 *   Data : 2019-09-12-15.15
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-7;
const LL mod = 1e9+7;
const int MX = 1e3+5;
double p1[MX][MX],p2[MX][MX],p3[MX][MX],dp[MX][MX];

int main(){
    int n,m;
    while(cin>>n>>m){
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
            scanf("%lf%lf%lf",&p1[i][j],&p2[i][j],&p3[i][j]);
        dp[n][m]=0;
        for(int i=n;i>=1;i--)for(int j=m;j>=1;j--){
            if(i==n&&j==m)continue;
            if(fabs(p1[i][j]-1)<=eps) {dp[i][j]=1e8;continue;} //不会走到这种点,但是需要continue
            dp[i][j]=(2.0+dp[i][j+1]*p2[i][j]+dp[i+1][j]*p3[i][j])/(1.0-p1[i][j]);
        }
        printf("%.3lf\n",dp[1][1]);
    }
    return 0;
}

Help Me Escape //倒推

题目

题 意 : 题意:
l y 初 始 战 斗 力 为 f , l y 周 围 有 n 条 路 , 每 条 路 上 有 一 个 妖 怪 , 战 斗 力 为 c [ i ] 。 ly初始战斗力为f,ly周围有n条路,每条路上有一个妖怪,战斗力为c[i]。 lyflync[i]
每 天 , l y 等 概 率 的 选 一 条 路 。 每天,ly等概率的选一条路。 ly
如 果 他 战 斗 力 大 于 c [ i ] , 那 么 他 花 t [ i ] 天 就 可 以 逃 出 去 。 如果他战斗力大于c[i],那么他花t[i]天就可以逃出去。 c[i]t[i]
否 则 他 战 斗 力 变 为 f + c [ i ] , 等 明 天 再 战 。 否则他战斗力变为f+c[i],等明天再战。 f+c[i]
求 l y 逃 出 去 的 天 数 的 期 望 求ly逃出去的天数的期望 ly

思 路 : 思路:
考 虑 倒 推 , 因 为 如 果 大 于 所 有 的 妖 怪 , 期 望 直 接 可 以 求 出 来 考虑倒推,因为如果大于所有的妖怪,期望直接可以求出来
d p [ i ] : 战 斗 力 为 i 时 , 逃 出 去 还 需 要 的 期 望 天 数 dp[i]:战斗力为i时,逃出去还需要的期望天数 dp[i]i

d p [ i ] = ∑ j = 1 n i &gt; c [ j ] ? t [ j ] : ( d p [ i + c [ j ] ] + 1 ) n dp[i]=\sum_{j=1}^n\frac{i&gt;c[j]?t[j]:(dp[i+c[j]]+1)}{n} dp[i]=j=1nni>c[j]?t[j]:(dp[i+c[j]]+1)
d p [ i n f ] = ∑ j = 1 n t [ j ] n dp[inf]=\sum_{j=1}^n\frac{t[j]}{n} dp[inf]=j=1nnt[j]

/*   Author : Rshs
 *   Data : 2019-09-12-16.00
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const LL mod = 1e9+7;
const int MX = 1e6+5;
int c[105];
double t[105],dp[MX];
int main(){
    int n,f;
    while(cin>>n>>f){
       int mx=2e4;
        for(int i=1;i<=n;i++){
            cin>>c[i];
            t[i]=(int)(1.0*c[i]*c[i]*(1.0+sqrt(5))/2);
        }
        for(int i=mx;i>=f;i--){
            dp[i]=0;
            for(int j=1;j<=n;j++){
                if(i>c[j]){
                    dp[i]=dp[i]+t[j]/(double)n; //成功
                }
                else {
                    dp[i]=dp[i]+(1.0+dp[i+c[j]])/(double)n; //失败
                }
            }
        }
        printf("%.3lf\n",dp[f]);
    }
    return 0;
}

hdu4035 Maze //循环解方程

题目

题意:
n n n个节点的树,从结点1出发,到每个结点 i i i有三个事件:
1. k i 1.k_i 1.ki概率被杀死回到节点 1 1 1
2. e i 2.e_i 2.ei概率找到节点上面的出口逃出并胜利
3. ( 1 − k i − e i ) 3.(1-k_i-e_i) 3.(1kiei)概率下等概率走一条相连的边
求胜利所要走的步数的期望

思路:

神 仙 题 目 了 . . . . . . . 神仙题目了....... .......

f ( i ) : 在 i 点 时 逃 出 所 需 要 的 期 望 次 数 f(i):在i点时逃出所需要的期望次数 f(i):i

叶 子 节 点 时 : 叶子节点时:
f ( i ) = e i ∗ 0 + k i ∗ f ( 1 ) + ( 1 − e i − k i ) ∗ ( f ( f a [ i ] ) + 1 ) f(i)=e_i*0+k_i*f(1)+(1-e_i-k_i)*(f(fa[i])+1) f(i)=ei0+kif(1)+(1eiki)(f(fa[i])+1)
f ( i ) = k i ∗ f ( 1 ) + ( 1 − e i − k i ) ∗ f ( f a [ i ] ) + 1 − e i − k i f(i)=k_i*f(1)+(1-e_i-k_i)*f(fa[i])+1-e_i-k_i f(i)=kif(1)+(1eiki)f(fa[i])+1eiki
非 叶 子 节 点 : 非叶子节点:
f ( i ) = e i ∗ 0 + k i ∗ f ( 1 ) + ( 1 − e i − k i ) d i ∗ ( f ( f a [ i ] ) + 1 ) + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) ( f ( j ) + 1 ) ) f(i)=e_i*0+k_i*f(1)+\frac{(1-e_i-k_i)}{d_i}*(f(fa[i])+1)+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}(f(j)+1)) f(i)=ei0+kif(1)+di(1eiki)(f(fa[i])+1)+di(1eiki)(json(i)(f(j)+1))
f ( i ) = k i ∗ f ( 1 ) + ( 1 − e i − k i ) d i ∗ f ( f a [ i ] ) + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) f ( j ) ) + 1 − e i − k i ① f(i)=k_i*f(1)+\frac{(1-e_i-k_i)}{d_i}*f(fa[i])+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}f(j))+1-e_i-k_i \quad ① f(i)=kif(1)+di(1eiki)f(fa[i])+di(1eiki)(json(i)f(j))+1eiki

设 f ( i ) = a i ∗ f ( 1 ) + b i ∗ f ( f a [ i ] ) + c i . 设f(i)=a_i*f(1)+b_i*f(fa[i])+c_i. f(i)=aif(1)+bif(fa[i])+ci.

对 于 ① 式 : 对于①式: :
f ( i ) = k i ∗ f ( 1 ) + ( 1 − e i − k i ) d i ∗ f ( f a [ i ] ) + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) ( a j ∗ f ( 1 ) + b j ∗ f ( f a [ j ] ) + c j ) ) + 1 − e i − k i f(i)=k_i*f(1)+\frac{(1-e_i-k_i)}{d_i}*f(fa[i])+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}(a_j*f(1)+b_j*f(fa[j])+c_j))+1-e_i-k_i f(i)=kif(1)+di(1eiki)f(fa[i])+di(1eiki)(json(i)(ajf(1)+bjf(fa[j])+cj))+1eiki
因 为 f a [ j ] = i : 因为 fa[j]=i: fa[j]=i:
f ( i ) = k i ∗ f ( 1 ) + ( 1 − e i − k i ) d i ∗ f ( f a [ i ] ) + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) ( a j ∗ f ( 1 ) + b j ∗ f ( i ) + c j ) ) + 1 − e i − k i f(i)=k_i*f(1)+\frac{(1-e_i-k_i)}{d_i}*f(fa[i])+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}(a_j*f(1)+b_j*f(i)+c_j))+1-e_i-k_i f(i)=kif(1)+di(1eiki)f(fa[i])+di(1eiki)(json(i)(ajf(1)+bjf(i)+cj))+1eiki
把 右 边 的 f ( i ) 移 到 左 边 : 把右边的f(i)移到左边: f(i)
f ( i ) ∗ ( 1 − ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) b j ) ) = f ( 1 ) ∗ ( k i + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) a j ) ) + ( 1 − e i − k i ) d i ∗ f ( f a [ i ] ) + 1 − e i − k i + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) c j ) f(i)*(1-\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}b_j))=f(1)*(ki+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}a_j))+\frac{(1-e_i-k_i)}{d_i}*f(fa[i])+1-e_i-k_i+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}c_j) f(i)(1di(1eiki)(json(i)bj))=f(1)(ki+di(1eiki)(json(i)aj))+di(1eiki)f(fa[i])+1eiki+di(1eiki)(json(i)cj)

可 得 : 可得:

a i = k i + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) a j ) 1 − ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) b j ) a_i=\frac{k_i+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}a_j)}{1-\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}b_j)} ai=1di(1eiki)(json(i)bj)ki+di(1eiki)(json(i)aj)
b i = ( 1 − e i − k i ) d i 1 − ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) b j ) b_i=\frac{\frac{(1-e_i-k_i)}{d_i}}{1-\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}b_j)} bi=1di(1eiki)(json(i)bj)di(1eiki)
c i = 1 − e i − k i + ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) c j ) 1 − ( 1 − e i − k i ) d i ∗ ( ∑ j ∈ s o n ( i ) b j ) c_i=\frac{1-e_i-k_i+\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}c_j)}{1-\frac{(1-e_i-k_i)}{d_i}*(\sum_{j∈son(i)}b_j)} ci=1di(1eiki)(json(i)bj)1eiki+di(1eiki)(json(i)cj)

这 时 候 一 个 神 奇 的 地 方 , 对 于 叶 子 节 点 这时候一个神奇的地方,对于叶子节点
a i = k i , b i = 1 − e i − k i , c i = 1 − e i − k i a_i=k_i,b_i=1-e_i-k_i,c_i=1-e_i-k_i ai=ki,bi=1eiki,ci=1eiki
那 么 从 叶 子 节 点 开 始 求 , 不 停 递 归 回 根 节 点 . 那么从叶子节点开始求,不停递归回根节点. .
∵ f ( 1 ) = a 1 ∗ f ( 1 ) + c 1 ∴ f ( 1 ) = c 1 1 − a 1 ∵ f(1)=a_1*f(1)+c_1\quad\quad∴f(1)=\frac{c_1}{1-a_1} f(1)=a1f(1)+c1f(1)=1a1c1
这 里 判 断 无 解 的 条 件 : a 1 趋 近 于 1 这里判断无解的条件:a_1趋近于1 a11

/*   Author : Rshs
 *   Data : 2019-09-12-19.20
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-9;
const LL mod = 1e9+7;
const int MX = 1e5+5;
double e[MX],k[MX];
double a[MX],b[MX],c[MX],aa[MX],bb[MX],cc[MX];
vector<int>g[MX];
void dfs(int v,int fa){
    aa[v]=bb[v]=cc[v]=0;
    for(auto i:g[v]){
        if(i==fa) continue;
        dfs(i,v);
        aa[v]+=a[i];bb[v]+=b[i];cc[v]+=c[i];
    }
    double zz=(1.0-e[v]-k[v])/(1.0*SZ(g[v]));
    a[v]=(k[v]+zz*aa[v])/(1.00-zz*bb[v]);
    b[v]=zz/(1.0-zz*bb[v]);
    c[v]=(1.0-e[v]-k[v]+zz*cc[v])/(1.0-zz*bb[v]);
}
void Main(int avg){
    int n;cin>>n;
    for(int i=1;i<=n;i++)g[i].clear();
    for(int i=1;i<n;i++){
        int sa,sb;scanf("%d%d",&sa,&sb);
        g[sa].push_back(sb);g[sb].push_back(sa);
    }
    for(int i=1;i<=n;i++)scanf("%lf%lf",&k[i],&e[i]),k[i]/=100.0,e[i]/=100.0;
    dfs(1,-1);
    printf("Case %d: ",avg);
    if(fabs(a[1]-1)<eps) {puts("impossible");return;}
    printf("%lf\n",c[1]/(1-a[1]));
}
int main(){
    int cas;cin>>cas;for(int i=1;i<=cas;i++)Main(i);
    return 0;
}

Bloodsucker //组合数

题目
题意:
n n n个人,一开始有一个吸血鬼,每天随机的从 n n n个人中挑出两个人,如果一个人是吸血鬼,一个人是普通人,那么普通人有 p p p的概率被感染,求全部人变成吸血鬼的期望天数。
思路:
定 义 d p [ i ] : 有 i 个 吸 血 鬼 时 , 全 部 变 成 吸 血 鬼 的 期 望 天 数 , d p [ n ] = 0. 定义dp[i]:有i个吸血鬼时,全部变成吸血鬼的期望天数,dp[n]=0. dp[i]:idp[n]=0.
第 i 天 感 染 一 个 人 的 概 率 为 : z = i ∗ ( n − i ) n ∗ ( n − 1 ) / 2 . 第i天感染一个人的概率为:z=\frac{i*(n-i)}{n*(n-1)/2}. iz=n(n1)/2i(ni).
d p [ i ] = ( 1 + d p [ i + 1 ] ) ∗ z + ( d p [ i ] + 1 ) ∗ ( 1 − z ) , 然 后 移 项 即 可 dp[i]=(1+dp[i+1])*z+(dp[i]+1)*(1-z),然后移项即可 dp[i]=(1+dp[i+1])z+(dp[i]+1)(1z),

/*   Author : Rshs
 *   Data : 2019-09-13-15.27
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MX = 1e6+5;
double dp[MX];
void Main(int avg){
    int n;double p;
    cin>>n>>p;
    dp[n]=0;
    for(int i=n-1;i>=1;i--){
        double x=(1.0*n-i)*2/(1.0*n);
        double y=1.0*i/(1.0*n-1);
        dp[i]=(1.0+dp[i+1]*x*y*p)/(x*y*p);
    }
    printf("%.3lf\n",dp[1]);
}
int main(){
    int cas;cin>>cas;for(int i=1;i<=cas;i++)Main(i);
    return 0;
}

CF #105 Div.2 D. Bag of mice//概率,二维

题目
题意:
w w w个白老鼠, b b b个黑老鼠, l y ly ly r s rs rs博弈,先取到白老鼠的人获胜, l y ly ly先手。
r s rs rs取的时候,会随机的跑掉一只老鼠。没人取到白老鼠 r s rs rs获胜。
l y ly ly获胜的期望.
思路:
定义 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]
k = = 0 k==0 k==0时:剩下 i i i个白老鼠, j j j个黑老鼠,轮到 l y ly ly取老鼠的概率。
k = = 1 k==1 k==1时:剩下 i i i个白老鼠, j j j个黑老鼠,轮到 r s rs rs取老鼠的概率。
最后从 ( w , b ) (w,b) (w,b)倒推矩阵到 ( 0 , 0 ) (0,0) (0,0),期间累加ly获胜情况下的概率。

/*   Author : Rshs
 *   Data : 2019-09-13-20.23
 */
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MX = 1e6+5;
double dp[1005][1005][2];
int main(){
    int w,b;
    cin>>w>>b;dp[w][b][0]=1;
    double ans=0;
    for(int i=w;i>=0;i--){
        for(int j=b;j>=0;j--){
            if(i==0&&j==0) continue;
            double p=(i*1.00)/(1.0*i+j);
            ans+=p*dp[i][j][0];
            if(j>=1)dp[i][j-1][1]+=(1.0-p)*dp[i][j][0];
            if(j>=2)dp[i][j-2][0]+=(1.0-p)*(1.0*j-1)/(1.0*j-1+i)*dp[i][j][1];
            if(j>=1&&i>=1) dp[i-1][j-1][0]+=(1.0-p)*(1.0*i)/(1.0*j-1+i)*dp[i][j][1];
        }
    }
    printf("%.12lf\n",ans);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值