zoukankan      html  css  js  c++  java
  • hdu4035 Maze 【期望dp + 数学】

    题目链接

    BZOJ4035

    题解

    神题啊。。。orz
    不过网上题解好难看,数学推导不写(Latex)怎么看。。【Latex中毒晚期

    我们由题当然能很快写出(dp)方程
    (f[i])表示从(u)出发逃离的期望步数,(m)为该点度数

    [egin{aligned} f[u] &= K_uf[1] + frac{1 - K_u - E_u}{m}sumlimits_{(u,v) in edge} (f[v] + 1)\ &= K_uf[1] + frac{1 - K_u - E_u}{m}f[fa[u]] + frac{1 - K_u - E_u}{m}sumlimits_{(u,v) in edge & v e fa[u]} f[v] + (1 - K_u - E_u)\ end{aligned} ]

    然后就会发现这个方程似乎有后效性,立即想高斯消元
    一看范围(n le 10^4)什么鬼嘛QAQ。。。

    题解是这么说的:
    我们设

    [f[u] = A_uf[1] + B_uf[fa[u]] + C_u ]

    对于叶子节点,显然有

    [egin{aligned} A_u &= K_u \ B_u &= 1 - K_u - E_u \ C_u &= 1 - K_u - E_u \ end{aligned} ]

    对于非叶节点,我们展开(f[v])

    [egin{aligned} f[u] &= K_uf[1] + frac{1 - K_u - E_u}{m}f[fa[u]] + frac{1 - K_u - E_u}{m}sumlimits_{(u,v) in edge & v e fa[u]} f[v] + (1 - K_u - E_u)\ &= K_uf[1] + frac{1 - K_u - E_u}{m}f[fa[u]] + frac{1 - K_u - E_u}{m}sumlimits_{(u,v) in edge & v e fa[u]} (A_vf[1] + B_vf[u] + C_v) + (1 - K_u - E_u)\ end{aligned} ]

    我们整理一下:

    [f[u] = frac{K_u + frac{1 - K_u - E_u}{m}sum A_v}{1 - frac{1 - K_u - E_u}{m}sum B_v}f[1] + frac{frac{1 - K_u - E_u}{m}}{1 - frac{1 - K_u - E_u}{m}sum B_v}f[fa[u]] + frac{1 - K_u - E_u - frac{1 - K_u - E_u}{m}sum C_v}{1 - frac{1 - K_u - E_u}{m}sum B_v} ]

    [egin{aligned} A_u &= frac{K_u + frac{1 - K_u - E_u}{m}sum A_v}{1 - frac{1 - K_u - E_u}{m}sum B_v} \ B_u &= frac{frac{1 - K_u - E_u}{m}}{1 - frac{1 - K_u - E_u}{m}sum B_v} \ C_u &= frac{1 - K_u - E_u - frac{1 - K_u - E_u}{m}sum C_v}{1 - frac{1 - K_u - E_u}{m}sum B_v} \ end{aligned} ]

    然后由于

    [egin{aligned} f[1] &= A_1f[1] + B_1 imes 0 + C_1 \ f[1] &= frac{C_1}{1 - A_1} end{aligned} ]

    (1 - A_1 = 0)时无解
    否则我们能直接计算出(f[1]),即为所求

    是不是很神奇?
    这个式子的推导主要是利用了式子中有(f[fa[u]])这一项,从而可以从儿子中递推出父亲的信息

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    #define eps 1e-10
    using namespace std;
    const int maxn = 10005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,h[maxn],ne,de[maxn],fa[maxn];
    struct EDGE{int to,nxt;}ed[maxn << 1];
    void build(int u,int v){
    	ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
    	ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
    	de[u]++; de[v]++;
    }
    double A[maxn],B[maxn],C[maxn],K[maxn],E[maxn];
    int dfs(int u){
    	if (de[u] == 1 && u != 1){
    		A[u] = K[u];
    		B[u] = C[u] = 1 - K[u] - E[u];
    		return true;
    	}
    	double m = de[u],tmp = 0;
    	A[u] = K[u];
    	B[u] = (1 - K[u] - E[u]) / m;
    	C[u] = 1 - K[u] - E[u];
    	Redge(u) if ((to = ed[k].to) != fa[u]){
    		fa[to] = u; if (!dfs(to)) return false;
    		A[u] += A[to] * B[u];
    		C[u] += C[to] * B[u];
    		tmp += B[to] * B[u];
    	}
    	if (fabs(1 - tmp) < eps) return false;
    	A[u] /= (1 - tmp); B[u] /= (1 - tmp); C[u] /= (1 - tmp);
    	return true;
    }
    int main(){
    	int T = read();
    	for (int t = 1; t <= T; t++){
    		n = read(); cls(de); cls(h); ne = 1;
    		for (int i = 1; i < n; i++) build(read(),read());
    		for (int i = 1; i <= n; i++) K[i] = read() / 100.0,E[i] = read() / 100.0;
    		printf("Case %d: ",t);
    		if (!dfs(1) || fabs(A[1] - 1) < eps) puts("impossible");
    		else printf("%.10lf
    ",C[1] / (1 - A[1]));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    JMeter学习(二十三)关联
    最常用的DOS命令
    不同类型的操作系统
    分级存储管理的四大优点
    软件工程中数据库设计
    PPP(点对点协议(Point to Point Protocol)
    关键路径法
    什么是鲁棒性测试
    何为蠕虫病毒
    临界区
  • 原文地址:https://www.cnblogs.com/Mychael/p/9077231.html
Copyright © 2011-2022 走看看