zoukankan      html  css  js  c++  java
  • 题解 HDU4035 Maze

    题意

    有一个树形的迷宫,你从根节点1出发,每一个节点有(k_i)的概率死去,并重新从节点1出发;有(e_i)的概率逃脱迷宫,从一个点有相等的概率穿过一次通道到达其他的点,求成功逃脱的期望次数

    节点数(nleq1e5)

    思路

    我们设(f(i))表示从i出发逃脱的期望次数,(deg_i)表示节点i的度

    一看就是一个期望题嘛,我们考虑如何树形DP

    由于求的时候会先算出子节点,我们将子节点与父节点分开来处理

    可以得到

    [f(i)=k_if(1)+frac{1-k_i-e_i}{deg_i}sum_{jin son(i)}(f(j)+1)+frac{1-k_i-e_i}{deg_i}(f(fa_i)+1) ]

    然后这个就会互相影响没法做了

    一般来说循环转移我们会去写高斯消元对不对,可是这道题你写会炸掉

    这样我们考虑一下别的

    观察到每一个状态转移方程中都有(f(1)),假设我们已经求得(f(1)),就可以求解出整个转移系统,且有形式化的(f_i=A_if(1)+B_if(fa_i)+C_i)

    (f(j)=A_jf(1)+B_jf(fa_j=i)+C_j)代入原式得

    [f(i)=k_if(1)+frac{1-k_i-e_i}{deg_i}sum_{jin son(i)}(A_jf(1)+B_jf(i)+C_j+1)+frac{1-k_i-e_i}{deg_i}(f(fa_i)+1) ]

    (D_i=frac{1-k_i-e_i}{deg_i}),然后按照形式整理一下式子

    [(1-d_isum_{jin son(i)}b_j)f_i=(k_i+D_isum_{jin son(i)}A_j)f(1)+D_if(fa_i)+D_i+D_i(sum_{jin son(i)}(C_j+1)) ]

    (T_i=1-d_isum_{jin son(i)}b_j)

    [A_i=frac{k_i+D_isum_{jin son(i)}A_j}{T_i} ]

    [B_i=frac{D_i}{T_i} ]

    [C_i=frac{D_i+D_i(sum_{jin son(i)}(C_j+1))}{T_i}=frac{D_i*deg_i+D_i(sum_{jin son(i)}C_j)}{T_i} ]

    (i=1)时,(f(1)=A_1f(1)+C_1),然后(f(1)=frac{C_1}{1-A_1})

    然后在树上跑DP从下往上求出(A,B,C)即可,注意若除数为0则无解

    注意下文代码中的(A,B,C)与上文并非对应关系,准确来说是(A,B)反了

    推得真辛苦

    代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const MAXN=1e5;
    double eps=1e-10;
    int TT,n,tot,cnt;
    double k[MAXN],e[MAXN],B[MAXN],A[MAXN],C[MAXN],d[MAXN],T[MAXN];
    int deg[MAXN],h[MAXN];
    bool flag;
    struct edge{
    	int to,next;
    }E[MAXN];
    void add(int u,int v){
    	E[++tot]=(edge){v,h[u]},h[u]=tot,deg[u]++;
    }
    void dfs(int x,int fa){
    	T[x]=1, B[x]=k[x], A[x]=d[x], C[x]=1-k[x]-e[x];
    	//if(deg[x]-1==0 && x!=1)return;
    	for(int i=h[x];i;i=E[i].next){
    		int to=E[i].to;
    		if(to==fa)continue;
    		dfs(to,x);
    		if(flag)return;
    		T[x]-=d[x]*A[to];
    		B[x]+=d[x]*B[to];
    		C[x]+=d[x]*C[to];
    	}
    	if(fabs(T[x]) < eps){flag=1;return;}
    	B[x]/=T[x];A[x]/=T[x];C[x]/=T[x];
    	return ;
    }
    int main(){
    	//freopen("a.in","r",stdin);
    	//freopen("a.out","w",stdout);
    	scanf("%d",&TT);
    	while(TT--){
    		scanf("%d",&n);
    		memset(h,0,sizeof(h));
    		memset(deg,0,sizeof(deg));
    		flag=0,tot=0;
    		for(int i=1,x,y;i<=n-1;i++){
    			scanf("%d%d",&x,&y);
    			add(x,y);add(y,x);
    		}
    		for(int i=1;i<=n;i++){
    			scanf("%lf%lf",&k[i],&e[i]);
    			k[i]/=100.0;e[i]/=100.0;
    			//printf("%lf %lf
    ",k[i],e[i]);
    		}
    		for(int i=1;i<=n;i++)
    			d[i]=(1-k[i]-e[i])/deg[i];
    		dfs(1,0);
    		printf("Case %d: ",++cnt);
    		//printf("%.18lf %.18lf
    ",fabs(1-B[1]),eps);
    		if(fabs(1-B[1])<eps || flag){
    			printf("impossible
    ");
    		}else{
    			printf("%.6lf
    ",C[1]/(1.0-B[1]));
    		}
    	}
    	return 0;
    }
    

    后记

    这道题体现出了循环转移方程的线性解法,关键在于有一个核心状态与所有状态有关,才能如此求解

  • 相关阅读:
    B
    A
    UVA
    马的移动(BFS) 详细注释 一个具有情怀的题目
    JAVA JDK 环境变量配置--简单图解
    linux系统(rpm与deb环境),JAVA JDK的配置
    Jmeter接口测试+压力测试+环境配置+证书导出
    LR访问Https接口
    GitHub linux 提交文件及403错误处理
    random模块写的验证码
  • 原文地址:https://www.cnblogs.com/fpjo/p/14002619.html
Copyright © 2011-2022 走看看