Hdu 4035 Maze 树上概率DP

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
  
  
3 3 1 2 1 3 0 0 100 0 0 100 3 1 2 2 3 0 0 100 0 0 100 6 1 2 2 3 1 4 4 5 4 6 0 0 20 30 40 30 50 50 70 10 20 60
 

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

Source


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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值