HDU4035:Maze

18 篇文章 0 订阅
9 篇文章 0 订阅

题目大意

传送门
在这里插入图片描述

思路

我们先考虑最朴素无华的dp,我们假设 d p [ i ] dp[i] dp[i]为从i点走出迷宫的期望步数,那么,我们可以费劲九牛二虎之力 轻松地列出dp式,如果i是叶子节点,那么

d p [ i ] = k i × d p [ 1 ] + e i × 0 + ( 1 − e i − k i ) × ( d p [ f a ] + 1 ) dp[i]=k_i\times dp[1]+e_i\times 0 + (1-e_i-k_i)\times (dp[fa]+1) dp[i]=ki×dp[1]+ei×0+(1eiki)×(dp[fa]+1) ⇒ d p [ i ] = k i × d p [ 1 ] + ( 1 − e i − k i ) × ( d p [ f a ] + 1 ) \Rightarrow dp[i]=k_i\times dp[1] + (1-e_i-k_i)\times (dp[fa]+1) dp[i]=ki×dp[1]+(1eiki)×(dp[fa]+1),

这句话什么意思呢?就是说它有 k i k_i ki的概率被杀死回到1点,它也有 e i e_i ei的可能走出迷宫,但是它是从i点走出去,所以它的贡献就是 e i × 0 e_i\times 0 ei×0不就是没有么?还在这里废话然后这个点还有 ( 1 − e i − k i ) (1-e_i-k_i) (1eiki)的概率继续走下去,贡献是 ( 1 − e i − k i ) × ( d p [ f a ] + 1 ) (1-e_i-k_i)\times (dp[fa]+1) (1eiki)×(dp[fa]+1),所以这就是叶子结点的情况。对于不是叶子节点的情况也差不多,不过某些部分需要除以它的度数(它走到每个相邻的点的概率都是一样的),所以大概就长成这个亚子:

d p [ i ] = k i × d p [ 1 ] + ( 1 − k i − e i ) × ( d p [ f a ] + 1 ) d e g [ i ] + ∑ s o n d p [ s o n ] + 1 d e g [ i ] dp[i]=k_i\times dp[1]+\frac{(1-k_i-e_i)\times (dp[fa]+1)}{deg[i]}+\frac{\sum_{son}{dp[son]+1}}{deg[i]} dp[i]=ki×dp[1]+deg[i](1kiei)×(dp[fa]+1)+deg[i]sondp[son]+1

⇒ \Rightarrow d p [ i ] = k i × d p [ 1 ] + ( 1 − e i − k i ) × ( d p [ f a ] + 1 + ∑ s o n ( d p [ s o n ] + 1 ) ) d e g [ i ] dp[i]=k_i\times dp[1]+\frac{(1-e_i-k_i)\times (dp[fa]+1+\sum_{son}(dp[son]+1))}{deg[i]} dp[i]=ki×dp[1]+deg[i](1eiki)×(dp[fa]+1+son(dp[son]+1)),

因为跟上面差不多,所以我就不详说了,但是我们会发现一个BUG,这个东西TMD 一直在来回地推,完全就是有递无归,我们难道要用高斯消元了么?不!这个TMD可能么?拜托, 1000 0 3 10000^3 100003,我们考虑一下树形动规,我们在后序遍历中,我们的 d p [ s o n ] dp[son] dp[son]是一个已知量,而 d p [ f a ] dp[fa] dp[fa] d p [ 1 ] dp[1] dp[1]是未知量,所以,我们就不做了我们考虑把 d p [ i ] dp[i] dp[i]表示为另一种形式,就长成

d p [ i ] = A [ i ] × d p [ f a ] + B [ i ] × d p [ 1 ] + C [ i ] dp[i]=A[i]\times dp[fa]+B[i]\times dp[1]+C[i] dp[i]=A[i]×dp[fa]+B[i]×dp[1]+C[i],
其中 A [ i ] , B [ i ] , C [ i ] A[i],B[i],C[i] A[i],B[i],C[i]都是我们自己要算出来的系数项。我们将

d p [ s o n ] = A [ s o n ] × d p [ i ] + B [ s o n ] × d p [ 1 ] + C [ s o n ] dp[son]=A[son]\times dp[i]+B[son]\times dp[1]+C[son] dp[son]=A[son]×dp[i]+B[son]×dp[1]+C[son]带入 d p [ i ] dp[i] dp[i]的表达式中,我们设 P [ i ] = 1 − e i − k i d e g [ i ] P[i]=\frac{1-e_i-k_i}{deg[i]} P[i]=deg[i]1eiki
因为

d p [ i ] = k i × d p [ 1 ] + P [ i ] × ( d p [ f a ] + 1 ) + P [ i ] × ∑ s o n ( d p [ s o n ] + 1 ) dp[i]=k_i\times dp[1]+P[i]\times(dp[fa]+1)+P[i]\times \sum_{son}(dp[son]+1) dp[i]=ki×dp[1]+P[i]×(dp[fa]+1)+P[i]×son(dp[son]+1),

也就是说

d p [ i ] = k i × d p [ 1 ] + P [ i ] × ( d p [ f a ] + 1 ) + P [ i ] × ∑ s o n ( A [ s o n ] × d p [ i ] + B [ s o n ] × d p [ 1 ] + C [ s o n ] ) dp[i]=k_i\times dp[1]+P[i]\times (dp[fa]+1)+P[i]\times \sum_{son}(A[son]\times dp[i]+B[son]\times dp[1]+C[son]) dp[i]=ki×dp[1]+P[i]×(dp[fa]+1)+P[i]×son(A[son]×dp[i]+B[son]×dp[1]+C[son])
在我们合并同类项之后就长成这个亚子:

( 1 − ∑ s o n A [ s o n ] × P [ i ] ) × d p [ i ] = d p [ f a ] × P [ i ] + ( ∑ s o n B [ s o n ] × P [ i ] + k i ) × d p [ 1 ] + ∑ s o n ( C [ s o n ] + 1 ) × P [ i ] + P [ i ] (1-\sum_{son}A[son]\times P[i])\times dp[i]=dp[fa]\times P[i]+(\sum_{son}{B[son]\times P[i]+k_i})\times dp[1]+\sum_{son}{(C[son]+1)}\times P[i]+P[i] (1sonA[son]×P[i])×dp[i]=dp[fa]×P[i]+(sonB[son]×P[i]+ki)×dp[1]+son(C[son]+1)×P[i]+P[i]
我们看着这个东西感觉非常的不爽,那我们就设 T [ i ] = 1 − ∑ s o n ( A [ s o n ] × P [ i ] ) T[i]=1-\sum_{son}(A[son]\times P[i]) T[i]=1son(A[son]×P[i]),那么根据之前 d p [ i ] = A [ i ] × d p [ f a ] + B [ i ] × d p [ 1 ] + C [ i ] dp[i]=A[i]\times dp[fa]+B[i]\times dp[1]+C[i] dp[i]=A[i]×dp[fa]+B[i]×dp[1]+C[i],所以我们两边同时除以 T [ i ] T[i] T[i],就得出:

A [ i ] = P [ i ] T [ i ] , B [ i ] = ∑ s o n ( B [ s o n ] × P [ i ] + K [ i ] ) T [ i ] , C [ i ] = ∑ s o n ( C [ s o n ] × P [ i ] + d e g [ i ] × P [ i ] ) T [ i ] A[i]=\frac{P[i]}{T[i]},B[i]=\frac{\sum_{son}(B[son]\times P[i]+K[i])}{T[i]},C[i]=\frac{\sum_{son}(C[son]\times P[i]+deg[i]\times P[i])}{T[i]} A[i]=T[i]P[i],B[i]=T[i]son(B[son]×P[i]+K[i]),C[i]=T[i]son(C[son]×P[i]+deg[i]×P[i])
所以,我们就可以跑一边树形动规就可以求出每个点的 A [ i ] , B [ i ] , C [ i ] A[i],B[i],C[i] A[i],B[i],C[i],我们发现点1它没有爸爸(它的妈妈是被强奸了么?),那我们就可以直接算出来,点1的dp值就是 C [ 1 ] 1.0 − B [ 1 ] \frac{C[1]}{1.0-B[1]} 1.0B[1]C[1],好,上面说了一大啪啦,但是,我们怎么判断有无解呢?实际上,我们只有除以0的时候才无解,所以在除以的时候判断一下就好了

代码理论AC

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

#define Int register int
#define MAXN 10005

int n;
int deg[MAXN];
double E[MAXN],K[MAXN],P[MAXN];
double A[MAXN],B[MAXN],C[MAXN];

vector <int> G[MAXN];

bool pd;

double Abs (double x){return x > 0 ? x : -x;}

void dfs (int u,int fa)
{
	double tmp = 0;
	double Au = P[u],Bu = K[u],Cu = 1 - K[u] - E[u];
	for (Int i = 0;i < G[u].size();++ i)
	{
		int v = G[u][i];
		if (v == fa) continue;
		dfs (v,u);
		if (pd) return ;
		Bu += B[v] * P[u];
		Cu += C[v] * P[u];
		tmp += A[v] * P[u];
	} 
	tmp = 1.0 - tmp;
	if (Abs (tmp) < 1e-10) 
	{
		pd = 1;
		return ;
	}
	A[u] = Au / tmp,B[u] = Bu / tmp,C[u] = Cu / tmp;
}

void read (int &x)
{
	x = 0;char c = getchar();int f = 1;
	while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}
	while (c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - '0';c = getchar();}
	x *= f;return ;
}

void write (int x)
{
	if (x < 0){x = -x;putchar ('-');}
	if (x > 9) write (x / 10);
	putchar (x % 10 + '0');
}

signed main()
{
	int times,tot = 0;
	read (times);
	while (times --)
	{	
		pd = 0;
		memset (G,0,sizeof (G));
		memset (E,0,sizeof (E));
		memset (K,0,sizeof (K));
		memset (P,0,sizeof (P));
		memset (A,0,sizeof (A));
		memset (B,0,sizeof (B));
		memset (C,0,sizeof (C));
		memset (deg,0,sizeof (deg));
		read (n);
		for (Int i = 1;i < n;++ i)
		{
			int u,v;
			read (u),read (v);
			G[u].push_back(v);
			G[v].push_back(u);
			deg[u] ++,deg[v] ++;
		}
		for (Int i = 1;i <= n;++ i)	 
		{
			scanf ("%lf%lf",&K[i],&E[i]);
			K[i] /= 100,E[i] /= 100;
		}
		for (Int i = 1;i <= n;++ i)
			P[i] = (1 - E[i] - K[i]) * 1.0 / deg[i];
		dfs (1,0);
		printf ("Case %d: ",++ tot);
		if (pd || Abs (1.0 - B[1]) < 1e-10) puts ("impossible");
		else printf ("%.6lf\n",C[1] / (1.0 - B[1]));
	}
}
/*
3
1 2
1 3
0 0
100 0
0 100
*/
//建议零的值设小一点,误差就小一点
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值