Hdu 4035 Maze 树上概率DP

来源:互联网 发布:淘宝上的大拿韩代 编辑:程序博客网 时间:2024/06/05 19:06

Maze

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 2842    Accepted Submission(s): 1212
Special Judge


Problem Description
When wake up, lxhgww find himself in a huge maze.

The maze consisted by N rooms and tunnels connecting these rooms. Each pair of rooms is connected by one and only one path. Initially, lxhgww is in room 1. Each room has a dangerous trap. When lxhgww step into a room, he has a possibility to be killed and restart from room 1. Every room also has a hidden exit. Each time lxhgww comes to a room, he has chance to find the exit and escape from this maze.

Unfortunately, lxhgww has no idea about the structure of the whole maze. Therefore, he just chooses a tunnel randomly each time. When he is in a room, he has the same possibility to choose any tunnel connecting that room (including the tunnel he used to come to that room).
What is the expect number of tunnels he go through before he find the exit?
 

Input
First line is an integer T (T ≤ 30), the number of test cases.

At the beginning of each case is an integer N (2 ≤ N ≤ 10000), indicates the number of rooms in this case.

Then N-1 pairs of integers X, Y (1 ≤ X, Y ≤ N, X ≠ Y) are given, indicate there is a tunnel between room X and room Y.

Finally, N pairs of integers Ki and Ei (0 ≤ Ki, Ei ≤ 100, Ki + Ei ≤ 100, K1 = E1 = 0) are given, indicate the percent of the possibility of been killed and exit in the ith room.
 

Output
For each test case, output one line “Case k: ”. k is the case id, then the expect number of tunnels lxhgww go through before he exit. The answer with relative error less than 0.0001 will get accepted. If it is not possible to escape from the maze, output “impossible”.
 

Sample Input
331 21 30 0100 00 10031 22 30 0100 00 10061 22 31 44 54 60 020 3040 3050 5070 1020 60
 

Sample Output
Case 1: 2.000000Case 2: impossibleCase 3: 2.895522
 

Source
The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest


So Sick...

一棵树,现在站在根部。在每个点上有三种可能:找到出口,回到根,向任何一个相邻节点移动一步(到每个节点都是等可能的)。问找到出口的期望步数。


先根据题意列出dp方程。dp[i]表示走到 i 号点之后需要继续走多少步才能找到出口,则可以根据三种转换关系列出方程,移项后可以求解。此时,对于每个叶节点上的dp[i],方程都为以下形式:

dp[i]=a*dp[1]+b*dp[father]+c

对于其他点,多了dp[son],其余项相同。

我们首先求出叶子节点上的参数a,b,c,之后带入到父节点。就这样一直回带,最终在根节点上可以将方程消到只剩dp[1]的形式。而dp[1]就是我们要求的答案。


#include <cstdio>#include <iostream>#include <string.h>#include <string>#include <vector>#include <algorithm>#include <math.h>#include <cmath>#define mem0(a) memset(a,0,sizeof(a))#define meminf(a) memset(a,0x3f,sizeof(a))using namespace std;typedef long long ll;typedef long double ld;typedef double db;const int maxn=10005,inf=0x3f3f3f3f;  const ll llinf=0x3f3f3f3f3f3f3f3f;   const db eps=1e-10;int head[maxn];db a[maxn],b[maxn],c[maxn],dp[maxn],k[maxn],e[maxn],son[maxn];bool visit[maxn];int num;struct Edge {int from,to,pre;};Edge edge[maxn*2];void addedge(int from,int to) {edge[num]=(Edge){from,to,head[from]};head[from]=num++;edge[num]=(Edge){to,from,head[to]};head[to]=num++;}bool dfs(int now,int fa) {visit[now]=1;a[now]=b[now]=c[now]=0.0;if (fa!=0) son[now]=1.0; else son[now]=0.0;for (int i=head[now];i!=-1;i=edge[i].pre) {int to=edge[i].to;if (!visit[to]) {son[now]+=1.0;if (!dfs(to,now)) return false;a[now]+=a[to];b[now]+=b[to];c[now]+=c[to];}}b[now]=1.0-b[now]*(1.0-k[now]-e[now])/son[now];a[now]=a[now]*(1.0-k[now]-e[now])/son[now]+k[now];c[now]=c[now]*(1.0-k[now]-e[now])/son[now]+(1.0-k[now]-e[now]);if (b[now]>eps) a[now]/=b[now],c[now]/=b[now]; else return false;b[now]=(1.0-k[now]-e[now])/(son[now]*b[now]);return true;}int main() {int cas,ca=0;scanf("%d",&cas);while (cas--) {ca++;num=0;memset(head,-1,sizeof(head));int i,j,x,y,n;scanf("%d",&n);for (i=1;i<n;i++) {scanf("%d%d",&x,&y);addedge(x,y);}for (i=1;i<=n;i++) {scanf("%lf%lf",&k[i],&e[i]);k[i]/=100.0;e[i]/=100.0;}mem0(visit);if (!dfs(1,0)) printf("Case %d: impossible\n",ca); else {if (fabs(1.0-a[1])>eps) {db ans=c[1]/(1.0-a[1]);printf("Case %d: %.6lf\n",ca,ans);} else printf("Case %d: impossible\n",ca);}}return 0;}