hdu4035.Maze

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

题意:给一个树状的迷宫,某个人一开始在第1个点,他想逃出这个迷宫,若他在第i个点,他有e[i]%的机会逃出迷宫,k[i]%被杀(若他被杀,则回到第一个点),或者等概率地走向一个相邻的点(这个人毫无记忆力),问这个人走出这个迷宫要经过的边数的期望值。

思路:以1号点为根建树,f[i]表示人在第i个点走出去的边数的期望值,则f[i] = e[i] + k[i]*f[1] + sigma((1-e[i]-k[i])/(ns+1)*(f[s]+1)) + (1-e[i]-k[i])/(ns+1)*(f[a]+1) // s为i的儿子,a为父亲,把式子化简,结合树dp的思想,各个点f[i]都可以归结为f[i] = A[i] + B[i]*f[1] + C[i]*f[a],儿子直接合并到父亲,从下往上dp到最后的结果是f[1] = A[1] + B[i] * f[1], 解一元一次方程即可。

程序:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define MAXN 10010
#define eps (1e-9)
#define INF 1000000000
#define sqr(x) ((x) * (x))
#define two(x) (1 << (x))
#define X first
#define Y second

typedef long long LL;

int n, ne;
int head[MAXN], k[MAXN], e[MAXN], ns[MAXN];
double A[MAXN], B[MAXN], C[MAXN];
pair<int, int> edge[MAXN * 2];
bool flag[MAXN];

void add_edge(int x, int y)
{
    ++ne;
    edge[ne] = make_pair(y, head[x]);
    head[x] = ne;
}

void init()
{
    ne = 0;
    memset(head, -1, sizeof(head));
    scanf("%d", &n);
    for (int i = 1; i < n; ++i)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        add_edge(x, y);
        add_edge(y, x);
    }
    for (int i = 1; i <= n; ++i) scanf("%d%d", &k[i], &e[i]);
}

void dfs(int x, int mark)
{
    int pnt = head[x];
    double ee = e[x] / 100.0, kk = k[x] / 100.0, u = (1 - ee - kk) / ns[x];
    double v = 0;
    if (mark == 0) 
        ns[x] = (x != 1);
    else
    {
        A[x] = 1 - kk;
        B[x] = kk;
        C[x] = u * (x != 1);
    }
    while (pnt != -1)
    {
        int y = edge[pnt].X;
        if (!flag[y])
        {
            flag[y] = true;
            dfs(y, mark);
            if (mark == 1)
            {
                A[x] += u * A[y];
                B[x] += u * B[y];
                v += u * C[y];
            }
            else
                ++ns[x];
        }
        pnt = edge[pnt].Y;
    }
    if (mark == 1)
    {
        A[x] /= (1 - v);
        B[x] /= (1 - v);
        C[x] /= (1 - v);
    }
}

void work()
{
    memset(flag, 0, sizeof(flag));
    flag[1] = true;
    dfs(1, 0);
    memset(flag, 0, sizeof(flag));
    flag[1] = true;
    dfs(1, 1);
    if (fabs(1 - B[1]) < eps) puts("impossible");
    else printf("%.6lf\n", A[1] / (1 - B[1]) - 1);
}

int main()
{
    int T, ca = 0;
    scanf("%d", &T);
    while (T--)
    {
        printf("Case %d: ", ++ca);
        init();
        work();
 //       for (int i = 1; i <= n; ++i) cout << A[i] << ' ' << B[i] << ' ' << C[i] << endl;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值