• 期望DP的一些题


    hdu3853

    题意:

    1. 题意:有一个迷宫r行m列,开始点在[1,1]现在要走到[r,c] 
    2. 对于在点[x,y]可以打开一扇门走到[x+1,y]或者[x,y+1] 
    3. 消耗2点魔力 
    4. 问平均消耗多少魔力能走到[r,c] 

    英语不好,只能看别人的翻译

    网上题解有些没说清楚,不管是走还是停,都会花费两点魔力值。

    很裸的期望DP,我记得有句很经典的话:终点是一切概率之末,确是一切期望之始。

    很好懂的Dp方程式:

    Dp[i][j]=(Dp[i+1][j]+2)*P1+(Dp[i][j+1]+2)*P2+(Dp[i][j]+2)*P0

    注意到P1+P2+P0=1;移相即可化简

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,m;
    double dp[1005][1005],p[1005][1005][3];
    int main()
    {
        while(~scanf("%d %d",&n,&m))
        {
            memset(dp,0,sizeof(dp));
            memset(p,0,sizeof(p));
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    scanf("%lf %lf %lf",&p[i][j][0],&p[i][j][1],&p[i][j][2]);
                }
            dp[n][m]=0;
            for(int i=n;i>=1;i--)
                for(int j=m;j>=1;j--)
                {
                    if(i==n&&j==m) continue;
                    if(p[i][j][0]==1) continue;
                    dp[i][j]=(p[i][j][1]*dp[i][j+1]+p[i][j][2]*dp[i+1][j]+2)/(1-p[i][j][0]);
                }    
            printf("%.3f
    ",dp[1][1]);    
        }
        
    }

    hdu4405:这道题更加简单,不用考虑留下来的概率,该怎么做就怎么做

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,vis[100010];
    double dp[100010];
    int main()
    {
        while(~scanf("%d %d",&n,&m)&&n)
        {
            memset(dp,0,sizeof(dp));
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=m;i++)
            {
                int a,b;
                scanf("%d %d",&a,&b);
                vis[a]=b;
            }
            for(int i=n-1;i>=0;i--)
            if(vis[i])  dp[i]=dp[vis[i]];else
            for(int j=1;j<=6;j++)
            dp[i]+=(dp[i+j]+1)/6.0;
            printf("%.4f
    ",dp[0]);
        }
     } 

     hdu4336

    其实懂了思路后很好写,反正就是常规套路。

    ans=sigma(last_ans+cost)*probablity+ans*probablity of remain

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    double dp[1100005],p[1005];
    int n;
    
    using namespace std;
    int main()
    {
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++)
            {
                scanf("%lf",&p[i]);
            }
            int l=(1<<n)-1;
            dp[l]=0;
            for(int sta=l-1;sta>=0;sta--)
            {
                double sum=0,tot=0;
                for(int j=1;j<=n;j++)
                if(!(sta&(1<<j-1)))
                sum+=p[j]*(dp[sta|(1<<j-1)]),tot+=p[j];
                sum+=1; 
                dp[sta]=sum/(tot);
            }
            printf("%.5f
    ",dp[0]);
        }
    }

     bzoj4832 

    小Q同学现在沉迷炉石传说不能自拔。他发现一张名为克苏恩的牌很不公平。如果你不玩炉石传说,不必担心,小Q
    同学会告诉你所有相关的细节。炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英雄,并且可以用牌
    召唤至多 7 个随从帮助玩家攻击对手,其中每个随从也拥有自己的血量和攻击力。小Q同学有很多次游戏失败都是
    因为对手使用了克苏恩这张牌,所以他想找到一些方法来抵御克苏恩。他去求助职业炉石传说玩家椎名真白,真白
    告诉他使用奴隶主这张牌就可以啦。如果你不明白我上面在说什么,不必担心,小Q同学会告诉你他想让你做什么
    。现在小Q同学会给出克苏恩的攻击力是 K ,表示克苏恩会攻击 K 次,每次会从对方场上的英雄和随从中随机选
    择一个并对其产生 1 点伤害。现在对方有一名克苏恩,你有一些奴隶主作为随从,每名奴隶主的血量是给定的。
    如果克苏恩攻击了你的一名奴隶主,那么这名奴隶主的血量会减少 1 点,当其血量小于等于 0 时会死亡,如果受
    到攻击后不死亡,并且你的随从数量没有达到 7 ,这名奴隶主会召唤一个拥有 3 点血量的新奴隶主作为你的随从
    ;如果克苏恩攻击了你的英雄,你的英雄会记录受到 1 点伤害。你应该注意到了,每当克苏恩进行一次攻击,你
    场上的随从可能发生很大的变化。小Q同学为你假设了克苏恩的攻击力,你场上分别有 1 点、 2 点、 3 点血量的
    奴隶主数量,你可以计算出你的英雄受到的总伤害的期望值是多少吗?
     
     
     

    Input

    输入包含多局游戏。
    第一行包含一个整数 T (T<100) ,表示游戏的局数。
    每局游戏仅占一行,包含四个非负整数 K, A, B 和 C ,表示克苏恩的攻击力是 K ,你有 A 个 1 点血量的奴隶
    主, B 个 2 点血量的奴隶主, C 个 3 点血量的奴隶主。
    保证 K 是小于 50 的正数, A+B+C 不超过 7 。
    这道题条件比较麻烦,直接写DP比较麻烦,用dfs+记忆化写方便
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    double vis[55][8][8][8],f[55][8][8][8];
    int T,k,a,b,c;
    double pro(int x,int a,int b,int c)
    {
        return double(x)/(a+b+c+1);
    }
    double dp(int k,int a,int b,int c)
    {
        if(!k) return 0;
        c=min(c,7-a-b);
        if(vis[k][a][b][c]) return f[k][a][b][c];
         
        vis[k][a][b][c]=1;
        f[k][a][b][c]+=pro(1,a,b,c)*(dp(k-1,a,b,c)+1);
        if(a)f[k][a][b][c]+=pro(a,a,b,c)*dp(k-1,a-1,b,c);
        if(b)f[k][a][b][c]+=pro(b,a,b,c)*dp(k-1,a+1,b-1,c+1);
        if(c)f[k][a][b][c]+=pro(c,a,b,c)*dp(k-1,a,b+1,c);
        return f[k][a][b][c];
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(vis,0,sizeof(vis));
            memset(f,0,sizeof(f));
            scanf("%d %d %d %d",&k,&a,&b,&c);
            printf("%.2f",dp(k,a,b,c));
        }
     } 

     bzoj1076

    【bzoj1076】[SCOI2008]奖励关
    2014年2月7日4,0871
    Description

    你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关。在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃)。 宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相互独立。也就是说,即使前k-1次系统都抛出宝物1(这种情况是有可能出现的,尽管概率非常小),第k次抛出各个宝物的概率依然均为1/n。 获取第i种宝物将得到Pi分,但并不是每种宝物都是可以随意获取的。第i种宝物有一个前提宝物集合Si。只有当Si中所有宝物都至少吃过一次,才能吃第i种宝物(如果系统抛出了一个目前不能吃的宝物,相当于白白的损失了一次机会)。注意,Pi可以是负数,但如果它是很多高分宝物的前提,损失短期利益而吃掉这个负分宝物将获得更大的长期利益。 假设你采取最优策略,平均情况你一共能在奖励关得到多少分值?

    Input

    第一行为两个正整数k和n,即宝物的数量和种类。以下n行分别描述一种宝物,其中第一个整数代表分值,随后的整数依次代表该宝物的各个前提宝物(各宝物编号为1到n),以0结尾。

    Output

    输出一个实数,保留六位小数,即在最优策略下平均情况的得分。

    比较明显的壮压+DP的期望题

    #include<cstdio>
    #include<iostream>
    using namespace std;
    double F[101][65536];
    int N,K,t;
    int v[20],d[20],p[20];
    int main()
    {
        for(int i=1;i<=16;i++)p[i]=1<<(i-1);
        scanf("%d%d",&N,&K);
        for(int i=1;i<=K;i++)
        {
            scanf("%d%d",&v[i],&t);
            while(t)
            {
                d[i]+=p[t];
                scanf("%d",&t);
            }
        }
        for(int i=N;i;i--)
            for(int j=0;j<=p[K+1]-1;j++)
            {
                for(int k=1;k<=K;k++)
                    if((d[k]&j)==d[k])
                       F[i][j]+=max(F[i+1][j],F[i+1][j|p[k]]+v[k]);
                    else F[i][j]+=F[i+1][j];
                F[i][j]/=K;
            }
        printf("%.6lf",F[1][0]);
        return 0;
    }
  • 相关阅读:
    让windows10的右键菜单既显示传统cmd又显示powershell
    配置php环境的一个nginx.conf
    windows中启动和终止nginx的两个批处理
    WxWidgets笔记
    安装archlinux的linux命令记录
    window中的attrib命令
    docker中i的作用
    airflow中的两个参数
    sqlite数据库中为字段设置默认值为当前时间
    记oracle使用expdp将数据导出到asm报错
  • 原文地址:https://www.cnblogs.com/dancer16/p/7683443.html
Copyright © 2020-2023  润新知