• HDU 4035 Maze(概率dp,一次函数递推)


    题目大意

      有一个树形的迷宫,从节点1开始走,每个节点都有(k_i)的概率回到1,(e_i)的概率逃出迷宫,每个房间有(m)条边相连,求走出迷宫所需步数的期望。

    解题思路

      设走出迷宫步数的期望为(E_i),父亲为(F_i),儿子为(S_i),相邻的节点个数为(m),则(E_1)即为所求。
      对于叶子节点来说,可以得到: (E_i = k_i imes E_1 + (1-k_i-e_i) imes (1 + E_{F_i}))
      即(E_i = k_i imes E_1 + (1-k_i-e_i) imes E_{F_i} + 1-k_i-e_i)
      对于非叶子节点来说,可以得到: (E_i = k_i imes E_1 + frac{(1-k_i-e_i)}{m} imes (1 + E_{F_i} + sum (E_{S_i} + 1)))
      即(E_i = k_i imes E_1 + frac{(1-k_i-e_i)}{m} imes E_{F_i} + frac{(1-k_i-e_i)}{m} imes sum E_{S_i} + 1-k_i-e_i)
      我们发现每个式子中都有(E_1)这个变量,这是不便于我们递推的,我们可以尝试把递推的值转为一次函数。
      设(E_i = A_i imes E_1 + B_i imes E_{F_i} + C_i), 那么将这个式带入非叶节点的公式替换掉(E_{S_i})可得:
      (E_i = k_i imes E_1 + frac{(1-k_i-e_i)}{m} imes E_{F_i} + frac{(1-k_i-e_i)}{m} imes (sum (A_{S_i} imes E_1 + B_{S_i} imes E_i + C_{S_i})) + 1-k_i-e_i)
      整理得: ((1 - frac{(1-k_i-e_i)}{m} imes sum B_{S_i}) imes E_i = (k_i + frac{(1-k_i-e_i)}{m} imes sum A_{S_i}) imes E_1 + frac{(1-k_i-e_i)}{m} imes E_{F_i} + 1-k_i-e_i + frac{(1-k_i-e_i)}{m} imes sum C_{S_i})

      (A_i = (k_i + frac{1-k_i-e_i}{m} imes sum A_{S_i}) / (1 - frac{1-k_i-e_i}{m} imes sum B_{S_i}))

      (B_i = (frac {1-k_i-e_i}{m}) / (1 - frac{1-k_i-e_i}{m} imes sum B_{S_i}))

      (C_i = (1-k_i-e_i + frac {1-k_i-e_i}{m} imes sum C_{S_i}) / (1 - frac{1-k_i-e_i}{m} imes sum B_{S_i}))
      这样我们通过递推出(A_1, B_1, C_1)就能得到答案了。

    代码

    const int maxn = 1e5+10;
    const int maxm = 2e6+10;
    double k[maxn], e[maxn];
    vector<int> g[maxn];
    int n;
    double a[maxn], b[maxn], c[maxn];
    void init() {
        clr(a, 0); clr(b, 0); clr(c, 0);
        for (int i = 0; i<=n; ++i) g[i].clear();
    }
    bool dfs(int u, int p) {
        double m = g[u].size();
        double pi = (1-k[u]-e[u])/m;
        double sum1 = k[u], sum2 = pi, sum3 = 1-k[u]-e[u], sum = 0;
        for (auto v : g[u]) {
            if (v==p) continue;
            if (!dfs(v, u)) return 0;
            sum1 += pi*a[v];
            sum += pi*b[v];
            sum3 += pi*c[v];
        }   
        sum = 1-sum;
        if (fabs(sum)<eps) return 0;
        a[u] = sum1/sum;
        b[u] = sum2/sum;
        c[u] = sum3/sum;
        return 1;
    }
    int main(void) { 
        //IOS;
        int __; cin >> __;
        int kase = 0;
        while(__--) {
            cin >> n;
            init();
            for (int i = 1; i<n; ++i) {
                int a, b; scanf("%d%d", &a, &b);
                g[a].push_back(b);
                g[b].push_back(a);
            }
            for (int i = 1; i<=n; ++i) {
                scanf("%lf", &k[i]); k[i] /= 100.0;
                scanf("%lf", &e[i]); e[i] /= 100.0;
            }
            
            if (dfs(1, -1) && fabs(1-a[1])>eps) printf("Case %d: %.6f
    ", ++kase, c[1]/(1-a[1]));
            else printf("Case %d: impossible
    ",  ++kase);
        }
    	return 0;   
    }
    
  • 相关阅读:
    ASP.NET 备份恢复SqlServer数据库
    ASP.NET MVC3.0 Razor 视图模板 语法
    ASP.NET 缓存
    代码生成框架
    C#中HashTable的用法
    C# 概念 委托和事件
    Web Service 系列 → Web Service 简介
    CDN 内容分发网络
    HarmonyOS开发者创新大赛
    #2020征文手表#【图解鸿蒙】多组示例演示三个样式的组合用法
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15131754.html
Copyright © 2020-2023  润新知