有向图或者无向图概率dp

概要:

一般形成环的用高斯消元法求解。但是递推公式只和少数变量相关,可以考虑分离出系数。

总结:

(看完下面的例题再来看这部分)

1.这类题型一般可以先写出原始公式然后分离出困难的变量,比如第二题的 dp[1] , dp[father[i]] , 都是很难处理的变量,就可以把它们作为待定系数的变量
2.将剩下的变量通过待定系数的公式带入消去,比如例题2, dp[child[i]] (Ajdp[1]+Bjdp[i]+Cj) (j=child[i])带入消去,从而找到关于系数A,B,C的递推公式
3.写出结果公式*用递推出的系数求出结果

例题1:HDU4405
题意:有三个骰子,分别有k1,k2,k3个面。
每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。
当分数大于n时结束。求游戏的期望步数。初始分数为0

设dp[i]表示达到i分时到达目标状态的期望,pk为投掷k分的概率,p0为回到0的概率
则dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;
都和dp[0]有关系,而且dp[0]就是我们所求,为常数
设dp[i]=A[i]*dp[0]+B[i];
代入上述方程右边得到:
dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1
=(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;
明显A[i]=(∑(pk*A[i+k])+p0)
B[i]=∑(pk*B[i+k])+1
先递推求得A[0]和B[0].
那么 dp[0]=B[0]/(1-A[0]);

#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using  namespace  std;

#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e5+10;

double dp[N];
int n, m;
int path[N], jump[N];

int  main(){
    while(~scanf("%d%d", &n, &m)){
        if(n == 0 && m == 0)break;
        mst(dp, 0);
        mst(path, -1);
        mst(jump, -1);
        for(int i=1; i<=m; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            path[u] = v;
        }

        for(int i=n; i>=1; i--){
            int j = path[i];
            if(j == -1)continue;
            if(jump[j] != -1)jump[i] = jump[j];
            else jump[i] = j;
        }

        for(int i=n-1; i>=0; i--){
            if(jump[i] != -1)dp[i] = dp[jump[i]];
            else{
                for(int j=1; j<=6; j++)
                    dp[i] += dp[i+j];
                dp[i] = dp[i]/6.0+1;
            }
        }
        printf("%.4f\n", dp[0]);
    }
    return 0;
}

例题2:HDU 4035

dp求期望的题。
题意:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。

这题是树上的概率dp,上题是有向图,这题是无向图,父子结点的概率互相影响。
设dp[i]表示从i号结点走出迷宫时走过边数的概率,father[i]表示i号结点的父亲结点,child表示i号结点的儿子结点

递推公式求法可参考kuangbin的题解
http://www.cnblogs.com/kuangbin/archive/2012/10/03/2711108.html

#include <bits/stdc++.h>
using  namespace  std;

#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define dbg(x) cout << #x << "= " << x << endl;
typedef pair <int, int> pii;
const int inf = 0x3f3f3f3f;
const int N = 1e4+5;
const double eps = 1e-12; //这题需要开小点

double k[N], e[N];
vector<int>E[N];
double A[N], B[N], C[N];
int n;

bool dfs(int u, int pre){
    int m = E[u].size();
    A[u] = k[u];
    B[u] = (1-k[u]-e[u])/m;
    C[u] = 1-k[u]-e[u];
    double tmp = 1.0;
    for(int i=0; i<m; i++){
        int v = E[u][i];
        if(v == pre)continue;
        if(!dfs(v, u))return 0;
        A[u] += (1-k[u]-e[u])/m*A[v];
        C[u] += (1-k[u]-e[u])/m*C[v];
        tmp -= (1-k[u]-e[u])/m*B[v];
    }
    if(fabs(tmp) < eps)return 0;
    A[u] /= tmp;
    B[u] /= tmp;
    C[u] /= tmp;
    return 1;
}

int  main(){
    int T;
    scanf("%d", &T);
    for(int kase=1; kase<=T; kase++){
        printf("Case %d: ", kase);
        scanf("%d", &n);
        for(int i=1; i<=n; i++)E[i].clear();
        for(int i=1; i<n; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            E[u].pb(v);
            E[v].pb(u);
        }
        for(int i=1; i<=n; i++){
            int x, y;
            scanf("%d%d", &x, &y);
            k[i] = x/100.0;
            e[i] = y/100.0;
        }

        if(dfs(1, -1) && fabs(1-A[1]) > eps)
            printf("%.6f\n", C[1]/(1-A[1]));
        else puts("impossible");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值