hdu 4035 Maze(期望)

http://acm.hdu.edu.cn/showproblem.php?pid=4035


是一道很好的题目。题意是有一个迷宫,这里有n个房间,每一对房间有且只有一条隧道,一共有n-1条隧道。起初他在1号房间。他若当前在房间i,接下来有三种路径可以走:ki的概率被杀掉直接回到1号房间;ei的概率从该房间逃走,否则它有均等的概率通过隧道走到和i号房间相连的房间。问它从1号房间逃出去要走的隧道数目的期望。


设dp[i]表示在i号房间走出去要通过的隧道的期望,n-1条边将房间连成一颗无根树,对于叶子节点,与它相连的只有一个父亲节点,那么dp[i] = ki * dp[1] + ei * 0 + (1-ki-ei) * ( dp[fa[i]] + 1);

对于非叶子节点

dp[i] = ki * dp[1] + ei * 0 + (1-ki-ei)/m * (∑dp[ son[i] ] + dp[ fa[i] ] + 1) 

= ki * dp[1] + (1-ki-ei)/m * dp[ fa[i] ]+ (1-ki-ei)/m * ∑dp[ son[i] ] + 1-ki-ei

可见dp[i]与dp[1],dp[fa[i]],dp[son[i]]有关。发现dp[fa[i]]和dp[son[i]]有关系,dp[son[i]]可通过dp[fa[i]]表示。那么设dp[i] = A[i] * dp[1] + B[i] * dp[fa[i]] + C[i]。

可以再列一个式子∑dp[son[i]] = ∑dp[j] = ∑(A[j] * dp[1] + B[j] * dp[i] + C[j])将该式子带入上式得:

dp[i] = ki * dp[1] + (1-ki-ei)/m * dp[ fa[i] ]+ (1-ki-ei)/m * ∑( A[j] * dp[1] + B[j] * dp[i] + C[j] ) + 1-ki-ei

最后得

(1-(1-ki-ei)/m*∑B[j])dp[i] = ( (1-ki-ei)/m*∑A[j] + ki)*dp[1] + (1-ki-ei)/m * dp[fa[i]] + (1-ki-ei)/m*∑C[j] + 1-ki-ei

对应之前设的dp[i] = A[i] * dp[1] + B[i]*dp[fa[i]] + C[i]可分别A[i],B[i],C[i]的递推式。

 那么dp[1] = C[1]/(1-A[1]),通过式子得如果A[i] == 1,说明无解。


#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL __int64
#define LL long long
#define eps 1e-9
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 10010;

vector <int> edge[maxn];
double e[maxn],k[maxn];
double A[maxn],B[maxn],C[maxn];
//无根树转化为有根树,1号房间为根节点
bool dfs(int u, int pre)
{
	int m = edge[u].size();
	double tmp = 0;
	A[u] = k[u];
	B[u] = (1-k[u]-e[u])/m;
	C[u] = 1-k[u]-e[u];
	for(int i = 0; i < (int)edge[u].size(); i++)
	{
		int v = edge[u][i];
		if(v == pre)
			continue;
		if(!dfs(v,u))
			return false;
		A[u] += (1-k[u]-e[u])/m * A[v];
		C[u] += (1-k[u]-e[u])/m * C[v];
		tmp += (1-k[u]-e[u])/m * B[v];
	}
	tmp = 1-tmp;
	if(fabs(tmp) < eps)
		return false;
	A[u] /= tmp;
	B[u] /= tmp;
	C[u] /= tmp;
	return true;
}

int main()
{
	int test,n;
	scanf("%d",&test);
	for(int item = 1; item <= test; item++)
	{
		scanf("%d",&n);
		int u,v;
		for(int i = 0; i <= maxn; i++)
			edge[i].clear();
		for(int i = 0; i < n-1; i++)
		{
			scanf("%d %d",&u,&v);
			edge[u].push_back(v);
			edge[v].push_back(u);
		}
		for(int i = 1; i <= n; i++)
		{
			scanf("%d %d",&u,&v);
			k[i] = u*1.0/100;
			e[i] = v*1.0/100;
		}
		printf("Case %d: ",item);
		if(dfs(1,-1) && fabs(A[1]-1) > eps)
		{
			printf("%.6lf\n",C[1]/(1-A[1]));
		}	
		else
			printf("impossible\n");
	}
	return 0;
}




你可能感兴趣的:(概率DP)