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;   
}
原文地址:https://www.cnblogs.com/shuitiangong/p/15131754.html