[hdu4035]Maze——树上高消
Posted ylsoi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[hdu4035]Maze——树上高消相关的知识,希望对你有一定的参考价值。
题目大意:
给定一颗树,从1号节点开始,在每个节点都有三种可能:
1.以(k_i)的概率回到1号节点
2.以(e_i)的概率走出迷宫
3.和该点相连的边随机走一条
求走出迷宫期望下走的步数。
思路:
首先设(p_i=1-k_i-e_i)。
设从第(i)个点出发,期望意义下走出迷宫需要走的步数为(f_i),那么我们得到的递推式是:
[
f_i=k_i imes f_1+p_i imes (1+frac{f_{fa}+sum_vf_v}{d_i})
]
不难发现这个递推式我们无法直接求解,它本质上是一个方程组,我们需要将这个方程组解开才能得到答案。
想到解方程组,大家都会想到高斯消元,但是普通的高斯消元在这个题目上显然不太行得通,因为它的时间复杂度为(n^3)。
考虑这个方程组有哪些特殊的性质,为了方便理解,我们先不考虑每个点的方程中和1号点有关的部分,这样以后可以发现方程其实也是一个树型结构,每一个点的方程关系到的变量只有它周围的点和它自己,这就使得我们可以尝试用线性的消元去解决这个问题。
考虑将1号点作为根之后,所有叶子节点它的方程中可以表示为:(f_i=A_i imes f_{fa}+B_i),那么我们如果在树上采用从子树递推的方式,当(u)的所有儿子都可以表示为上述形式的时候,我们直接采用带入消元的方法将它的所有儿子消去,由于带入的元素必定是它自己,(u)号点也成功地变成了上面这种形式。这个时候只要一直带入就可以得到1号点最终的(dp)值了。
这个时候再来考虑带1号点的情况,其实只需要将方程表示为(f_i=A_i imes f_{fa}+B_i imes f_1+C_i)的形式就好了,这样到了一号点之后还需要解一个一次方程。
这种消元的方式称作树上高斯消元。
下面是无聊的推式子。
[ egin{aligned} f_u&=k_u imes f_1+p_u imes (1+frac{f_{fa}+sum_vf_v}{d_u})f_u&=k_u imes f_1+p_u imes (1+frac{f_{fa}+sum_vA_v imes f_u+B_v imes f_1+C_v}{d_u})A_{u}&=frac{frac{p_u}{d_u}}{1-frac{p_u}{d_u}sum_vA_v}, B_{u}=frac{k_u+frac{p_u}{d_u}sum_vB_v}{1-frac{p_u}{d_u}sum_vA_v}, C_{u}=frac{p_u+frac{p_u}{d_u}sum_cC_v}{1-frac{p_u}{d_u}sum_vA_v} end{aligned} ]
/*=======================================
* Author : ylsoi
* Time : 2019.2.10
* Problem : hdu4035
* E-mail : [email protected]
* ====================================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;
using namespace std;
void File(){
freopen("hdu4035.in","r",stdin);
freopen("hdu4035.out","w",stdout);
}
template<typename T>void read(T &_){
_=0; T f=1; char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
_*=f;
}
const int maxn=1e4+10;
int T,n,d[maxn];
vector<int>G[maxn];
double k[maxn],e[maxn],p[maxn],A[maxn],B[maxn],C[maxn];
void dfs(int u,int fh){
double sa=0,sb=0,sc=0;
REP(i,0,G[u].size()-1){
int v=G[u][i];
if(v==fh)continue;
dfs(v,u);
sa+=A[v];
sb+=B[v];
sc+=C[v];
}
double mul=p[u]/d[u];
A[u]=mul/(1-mul*sa);
B[u]=(k[u]+mul*sb)/(1-mul*sa);
C[u]=(p[u]+mul*sc)/(1-mul*sa);
}
bool judge(int u,int fh){
if(e[u]!=0)return true;
if(p[u]==0)return false;
REP(i,0,G[u].size()-1){
int v=G[u][i];
if(v==fh)continue;
if(judge(v,u))return true;
}
return false;
}
int main(){
File();
read(T);
REP(ca,1,T){
read(n);
int u,v;
REP(i,1,n-1){
read(u),read(v);
G[u].pb(v),++d[v];
G[v].pb(u),++d[u];
}
REP(i,1,n){
scanf("%lf%lf",&k[i],&e[i]);
k[i]/=100,e[i]/=100;
p[i]=1-k[i]-e[i];
}
if(!judge(1,0))printf("Case %d: impossible
",ca);
else{
dfs(1,0);
printf("Case %d: %.10lf
",ca,C[1]/(1-B[1]));
}
REP(i,1,n)G[i].clear();
memset(d,0,sizeof(d));
}
return 0;
}
以上是关于[hdu4035]Maze——树上高消的主要内容,如果未能解决你的问题,请参考以下文章