zoukankan      html  css  js  c++  java
  • [HDU4035] Maze

    前言

    如果没有提示的话,应该很难吧,即使有了提示我也觉得这是个妙妙题。

    接下来是超详细讲解,面对长长的式子,请耐心看完,一定会有收获的!

    题目

    HDU

    VJudge

    题目大意:

    (T) 组数据。

    初始时勇敢牛牛在一个 (n) 个点的树的 (1) 号节点上,如果勇敢牛牛在节点 (i),则:

    • (K_i) 的概率被击杀,然后返回 (1) 号节点;
    • (E_i) 的概率直接找到出口逃出;
    • 等概率地在节点 (i) 的所有边中选择一条走。

    询问逃出生天的期望走的边数,如果无法逃出生天,输出 ( t impossible)

    注意:输入给的 (K_i)(E_i) 为百分数,并且保证为整数,且 (E_1=K_1=0)

    (1le Tle 3; 1le n le 10^5; 0le K_i,E_ile100; K_i+E_ile100.)

    讲解

    由于期望 (E) 和题目中的概率 (E_i) 重复了,所以我们把 (E_i,K_i) 变为 (es_i,ki_i(escape & kill)),而且这样和代码中的定义相同。

    如果没看到数据范围,你可能会天真地想高斯消元,可现实是残酷的,但你也得勇敢面对。

    勇敢牛牛,不怕困难!我们以 (1) 为根,直接把式子列出来树形DP!

    (E_i) 表示从 (i) 为起点逃生的期望边数,(deg_i)(i) 节点的度数,(fa_i)(i) 节点的父亲,则有:

    [E_i=ki_i imes E_1+es_i imes 0+frac{(1-ki_i-es_i)}{deg_i} imes(E_{fa_i}+1+sum (E_{son}+1)) ]

    可以发现,最难处理的是 (E_{fa_i}),如果它可以丢掉或者转换成其它形式,那么问题就迎刃而解了。

    我们可以将 (E_{fa_i}) 丢给 (fa_i) 自己处理!我们将转移的东西分一下类,然后重新写一下 (E_i) 的表达式:

    [egin{aligned} E_i&=ki_i imes E_1+frac{(1-ki_i-es_i)}{deg_i} imes(E_{fa_i}+1+sum (E_{son}+1))\ &=ki_i imes E_1+frac{(1-ki_i-es_i)}{deg_i} imes E_{fa_i}+frac{(1-ki_i-es_i)}{deg_i} imes(sum E_{son}+deg_x)\ &=ki_i imes E_1+frac{(1-ki_i-es_i)}{deg_i} imes E_{fa_i}+frac{(1-ki_i-es_i)}{deg_i} imessum E_{son}+(1-ki_i-es_i)\ end{aligned} ]

    我们将 (E_1) 的系数叫做 (A_i)(E_{fa_i}) 的系数叫做 (B_i),常数项叫做 (C_i),有:

    [egin{aligned} &E_i=A_i imes E_1+B_i imes E_{fa_i}+C_i\ &A_i=ki_i\ &B_i=frac{(1-ki_i-es_i)}{deg_i}\ &C_i=frac{(1-ki_i-es_i)}{deg_i} imessum E_{son}+(1-ki_i-es_i)\ end{aligned} ]

    然后我们将 (E_{son}) 拆开看看会发生什么:

    [egin{aligned} E_i&=A_i imes E_1+B_i imes E_{fa_i}+C_i\ &=A_i imes E_1+B_i imes E_{fa_i}+(1-ki_i-es_i)\ & +frac{(1-ki_i-es_i)}{deg_i} imessum (A_{son} imes E_1+B_{son} imes{E_i}+C_{son})\ (1-frac{(1-ki_i-es_i)}{deg_i}sum B_{son})E_i&=(A_i+frac{(1-ki_i-es_i)}{deg_i}sum A_{son}) imes E_1+B_i imes E_{fa_i}\ & +frac{(1-ki_i-es_i)}{deg_i}sum C_{son}+(1-ki_i-es_i)\ end{aligned} ]

    式子已经长得一行需要分行写了,我们令 (cao=1-ki_i-es_i,woc=frac{(1-ki_i-es_i)}{deg_i}),有:

    [egin{aligned} (1-wocsum B_{son})E_i&=(A_i+wocsum A_{son}) imes E_1+B_i imes E_{fa_i}+wocsum C_{son}+cao\ E_i&=frac{A_i+wocsum A_{son}}{1-wocsum B_{son}} imes E_1+frac{B_i}{1-wocsum B_{son}} imes E_{fa_i}+frac{wocsum C_{son}+cao}{1-wocsum B_{son}}\ end{aligned} ]

    至此,转移已经全部完毕。

    对于 (E_1=A_1 imes E_1+B_1 imes E_{fa_1}+C_1(E_{fa_1}=0)),易得 (E_1=frac{C_1}{1-A_1})

    如果 (A_1) 趋近于 (1) 则永远被困,否则输出答案即可。

    代码

    注意多组清空。

    点击查看
    //12252024832524
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 100005;
    const double eps = 1e-10;
    int n,cas,deg[MAXN];
    double ki[MAXN],es[MAXN],A[MAXN],B[MAXN],C[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int head[MAXN],tot;
    struct edge
    {
    	int v,nxt;
    }e[MAXN << 1];
    void Add_Edge(int x,int y)
    {
    	e[++tot].v = y;
    	e[tot].nxt = head[x];
    	head[x] = tot;
    	deg[x]++;
    }
    void Add_Double_Edge(int x,int y)
    {
    	Add_Edge(x,y);
    	Add_Edge(y,x);
    }
    void dfs(int x,int fa)
    {
    	double cao = 1-ki[x]-es[x],cs = 1,woc = (1-ki[x]-es[x])/deg[x];
    	A[x] = ki[x]; B[x] = woc; C[x] = cao;
    	for(int i = head[x],v; i ;i = e[i].nxt)
    	{
    		v = e[i].v;
    		if(v == fa) continue;
    		dfs(v,x);
    		A[x] += woc*A[v];
    		C[x] += woc*C[v];
    		cs -= woc*B[v];
    	}
    	A[x] /= cs; B[x] /= cs; C[x] /= cs;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	for(int T = Read(); T ;-- T)
    	{
    		n = Read(); tot = 0;
    		for(int i = 1;i <= n;++ i) deg[i] = head[i] = 0,A[i] = B[i] = C[i] = 0;
    		for(int i = 1;i < n;++ i) Add_Double_Edge(Read(),Read());
    		for(int i = 1;i <= n;++ i) ki[i] = Read() / 100.0,es[i] = Read() / 100.0;
    		printf("Case %d: ",++cas);
    		dfs(1,0);
    		if(Abs(1-A[1]) < eps) printf("impossible
    ");
    		else printf("%.6f
    ",C[1] / (1-A[1]));
    	}
    	return 0;
    }
    

    后记

    以后转移互相包含可以试着分类处理,实在搞不定给下一个状态接着搞。

    希望没人看出来不文明用语。

  • 相关阅读:
    揭秘青岛富二代接班路线 曝红领集团小美女总裁(图)-青青岛社区
    EF架构~TransactionScope与SaveChanges的关系
    LindAgile.Modules模块化的设计
    Linux~其实shell脚本也很简单
    Node.js~ioredis处理耗时请求时连接数瀑增
    Mongodb在CSharp里实现Aggregate
    微创业怎么样:微创业是否是以后的潮流?
    轻量级C语言实现的minixml解析库入门教程
    服务器:RAID、AHCI、IDE
    java web filter 之一 基础实现
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15046505.html
Copyright © 2011-2022 走看看