hdu 4035 概率DP 成都网赛

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

学到:

1、先判断是不是树,其实凡是有图的感觉的,都看边数==点数-1是不是成立

2、树有时候区分老子跟孩子还是有必要的,这道题就是,不过是在dfs的时候,传参数的时候多加个表示父节点的参数而已

3、一定注意,概率DP对精度真的要求很高 开始的时候写1e-8,WA了好几发,改了1e-10  AC

4、注意分母为0的可能的时候加上判断

讲的很详细的题解:http://blog.csdn.net/morgan_xww/article/details/6776947

直接按公式写的代码就是:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
const ll ll_INF = ((ull)(-1))>>1;
const double EPS = 1e-10;
const int INF = 100000000;
const int MAXN = 10000+100;

vector<int>g[MAXN];
double k[MAXN],e[MAXN];
double a[MAXN],b[MAXN],c[MAXN];
int n;

bool sea(int i, int fa)
{
    if(g[i].size() == 1 && fa!=-1)//叶子节点
    {
        a[i]=k[i];
        c[i]=b[i]=1.0-k[i]-e[i];
        return true;
    }
    //非叶子节点,此时该非叶子节点的子孙都已经遍历过了
    double aa=0.0,bb=0.0,cc=0.0;
    for(int j=0;j<g[i].size();j++)
    {
        if( g[i][j] == fa)continue;
        if(!sea(g[i][j],i))return 0;
        aa+=a[g[i][j]];
        bb+=b[g[i][j]];
        cc+=c[g[i][j]];
    }
    int m=g[i].size();
    a[i]=(k[i]+(1-k[i]-e[i])/m*aa)/(1-(1.0-k[i]-e[i])/m*bb);
    b[i]=(1.0-k[i]-e[i])/m/(1.0-(1.0-k[i]-e[i])/m*bb);
    c[i]=( (1.0-k[i]-e[i])+(1.0-k[i]-e[i])/m*cc )/(1.0 -(1.0-k[i]-e[i])/m*bb);
    return true;
}

int main()
{
    int ncase,u,v,ic=0;

    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            g[i].clear();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&k[i],&e[i]);
            k[i]/=100.0;
            e[i]/=100.0;
        }

        printf("Case %d: ",++ic);
        if(sea(1,-1) && fabs(1.0-a[1])>EPS)
            printf("%.6lf\n",c[1]/(1.0-a[1]));
        else
            printf("impossible\n");
    }
    return 0;
}

当然更好的写法还是题解上的

#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>  

using namespace std;  

const int MAXN = 10000 + 5;  

double e[MAXN], k[MAXN];
double A[MAXN], B[MAXN], C[MAXN];  

vector<int> v[MAXN];  

bool search(int i, int fa)
{
    if ( v[i].size() == 1 && fa != -1 )
    {
        A[i] = k[i];
        B[i] = 1 - k[i] - e[i];
        C[i] = 1 - k[i] - e[i];
        return true;
    }  

    A[i] = k[i];
    B[i] = (1 - k[i] - e[i]) / v[i].size();
    C[i] = 1 - k[i] - e[i];
    double tmp = 0;  

    for (int j = 0; j < (int)v[i].size(); j++)
    {
        if ( v[i][j] == fa ) continue;
        if ( !search(v[i][j], i) ) return false;
        A[i] += A[v[i][j]] * B[i];
        C[i] += C[v[i][j]] * B[i];
        tmp  += B[v[i][j]] * B[i];
    }
    if ( fabs(tmp - 1) < 1e-10 ) return false;
    A[i] /= 1 - tmp;
    B[i] /= 1 - tmp;
    C[i] /= 1 - tmp;
    return true;
}  

int main()
{
    int nc, n, s, t;  

    cin >> nc;
    for (int ca = 1; ca <= nc; ca++)
    {
        cin >> n;
        for (int i = 1; i <= n; i++)
            v[i].clear();  

        for (int i = 1; i < n; i++)
        {
            cin >> s >> t;
            v[s].push_back(t);
            v[t].push_back(s);
        }
        for (int i = 1; i <= n; i++)
        {
            cin >> k[i] >> e[i];
            k[i] /= 100.0;
            e[i] /= 100.0;
        }  

        cout << "Case " << ca << ": ";
        if ( search(1, -1) && fabs(1 - A[1]) > 1e-10 )
            cout << C[1]/(1 - A[1]) << endl;
        else
            cout << "impossible" << endl;
    }
    return 0;
} 
时间: 2024-10-19 11:50:19

hdu 4035 概率DP 成都网赛的相关文章

hdu 4035 概率dp

太吊了 1 /* 2 HDU 4035 3 4 dp求期望的题. 5 题意: 6 有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树, 7 从结点1出发,开始走,在每个结点i都有3种可能: 8 1.被杀死,回到结点1处(概率为ki) 9 2.找到出口,走出迷宫 (概率为ei) 10 3.和该点相连有m条边,随机走一条 11 求:走出迷宫所要走的边数的期望值. 12 13 设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望.E[1]即为所求. 14 15 叶子结点: 16 E[i] =

hdu 4035 可能性DP 成都网络游戏

http://acm.hdu.edu.cn/showproblem.php?pid=4035 获得: 1.首先推断是不是树.事实上,所有的感觉身影,既看边数==算-1是不成立 2.有时候,我告诉孩子来区分树仍然是必要的,就是,只是是在dfs的时候,传參数的时候多加个表示父节点的參数而已 3.一定注意,概率DP对精度真的要求非常高 開始的时候写1e-8,WA了好几发,改了1e-10  AC 4.注意分母为0的可能的时候加上推断 讲的非常具体的题解:http://blog.csdn.net/morg

hdu 4405 概率dp 2012年金华亚洲网络赛--虽然水,但是是自己独立做的第一道概率dp

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4405 e[i]:当前在位置i还需要走的步数期望 受刘汝佳的AC自动机那个后缀链接写法的启发,我的x[i]通过逆序算出来连续有"flight line "的时候,能到达的最远距离, rep(i,0,m) { scanf("%d%d",&xx,&yy); x[xx]=yy; } for(int i=n;i>=0;i--) if(x[i]!=-1 &

hdu 3853 概率DP 简单

http://acm.hdu.edu.cn/showproblem.php?pid=3853 题意:有R*C个格子,一个家伙要从(0,0)走到(R-1,C-1) 每次只有三次方向,分别是不动,向下,向右,告诉你这三个方向的概率,以及每走一步需要耗费两个能量,问你走到终点所需要耗费能量的数学期望: 回头再推次,思想跟以前的做过的类似 注意点:分母为0的处理 #include <cstdio> #include <cstring> #include <algorithm>

HDU 3853 概率dp

LOOPS Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others) Total Submission(s): 2337    Accepted Submission(s): 951 Problem Description Akemi Homura is a Mahou Shoujo (Puella Magi/Magical Girl).Homura wants to help he

hdu 4870(概率Dp)

首先我们以50分为一单位,于是赢一次得1分输一次扣2分,由于每次都用小号打,所以容易观察出最后达到20分时应该分别为20分和19分.我们设dp[i]为i到i+1分的期望步数.则dp[i]=p*1+(1-p)*(dp[i-2]+dp[i-1]+dp[i]+1),前者是赢的期望,后者由于输了2分,所以变成i+1分时需要从i-2->i-1->i->i+1,就是dp[i-2]+dp[i-1]+dp[i]+1了,f[i][j]表示大号为i分小号为j分的步数期望,Dp即可 代码https://git

hdu 4465 Candy 2012 成都现场赛

1 /** 2 对于大数的很好的应用,,缩小放大,,保持精度 3 **/ 4 #include <iostream> 5 #include <cmath> 6 #include <algorithm> 7 #include <cstdio> 8 using namespace std; 9 10 int main() 11 { 12 double n,p; 13 int cnt =1; 14 while(cin>>n>>p){ 15

HDU 5045 状压DP 上海网赛

比赛的时候想的是把n个n个的题目进行状压 但这样不能讲究顺序,当时精神面貌也不好,真是挫死了 其实此题的另一个角度就是一个n个数的排列,如果我对n个人进行状压,外面套一个按题目循序渐进的大循环,那么,在当前做第i个题目,前i-1个题目已经做完,然后做完的人的状态为j, j可能是1110 1101 1011什么的(假设已经做了三道题),因为我这样就可以只管状态而不管顺序了,我只取这种状态下的最大值,他究竟是怎么个顺序排列我不用管 到此...好像问题就没有什么问题了,这种做法重复 m/n次最后把剩余

hdu 5001 概率DP 图上的DP

http://acm.hdu.edu.cn/showproblem.php?pid=5001 当时一看是图上的就跪了 不敢写,也没退出来DP方程 感觉区域赛的题  一则有一个点难以想到 二则就是编码有点难度. 这个题: 我一直的思路就是1-能到达i的概率 就是不能到达i的概率,然后三维方程巴拉巴拉,,,,把自己搞迷糊 正确做法: dp[k][j]   经过j步到达k点 并且不经过i点的概率 这么设的原因是,就可以求不能到达i点的概率了.   不能到达i点的概率就是segma(dp[v][j-1]