概率DP(每天一道 舒舒服服~)

hhhh

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
#define bug(x) cout<<#x<<"=="<<x<<endl;
double dp[1005][1005];
struct node
{
    double yd;
    double ydx;
    double ydy;
}a[1005][1005];
int main()
{
    int r,c;
    while(scanf("%d %d",&r,&c)!=EOF)
    {
          for(int i=1;i<=r;i++)
    {
        for(int j=1;j<=c;j++)
        {
            scanf("%lf %lf %lf",&a[i][j].yd,&a[i][j].ydx,&a[i][j].ydy);
        }
    }
    dp[r][c]=0;
    for(int i=r;i>=1;i--)
    {
        for(int j=c;j>=1;j--)
        {
            if(a[i][j].yd==1.00||(i==r&&j==c))
            {
                continue;
            }
            dp[i][j]=(a[i][j].ydx*dp[i][j+1]+a[i][j].ydy*dp[i+1][j]+2)/(1.0-a[i][j].yd);
        }
    }
    printf("%.3f\n",dp[1][1]);
    }
  
}
/*#define mid (l+r)>>1
#define lr root*2
#define rr root*2+1
struct edge
{
    int to,next;
}e[maxn*2];
int head[maxn] = { 0 };
int tot=0;
void add(int x,int y)
{
    tot++;
    e[tot]=(edge){y,head[x]};
    head[x] = tot;
}
int dep[maxn],fa[maxn],siz[maxn];
///深度,父亲结点。子树大小
int son[maxn],dfn[maxn],top[maxn];
///重儿子,每一个结点通过冲链排序出来的顺序就是dfn也是他的dfs序,每一个结点所在的重链的顶点
int dfs1(int x,int Fa,int Dep)
{
    dep[x]=Dep,fa[x]=Fa,siz[x]=1;
    int maxson=1;///头结点
    for(int i=head[x];~i;i=e[i].next)
    {
        siz[x] += dfs1(e[i].to,x,Dep+1);
        if( siz[ e[i].to ] >maxson)
        {
            maxson = siz[ e[i].to ];
            son[x] = e[i].to;
            ///记录最大的重儿子
        }
    }
    return siz[x];
}
int cnt=0;///给每一个点标记编号
void dfs2(int x,int Top)
{
    cnt++;
    dfn[x]=cnt;
    top[x]=Top;
    if(!son[x])return ;
    ///叶子结点不需要计算啦
    dfs2(son[x],Top);
    for(int i=head[x];~i;i=e[i].next)
    {
        if(!dfn[ e[i].to ])
        ///说明e[i].to为x的轻儿子,他现在是自己子树的重链的起点,所以是Top
        {
            dfs2(e[i].to,e[i].to);
        }
    }
}

struct node
{
    int l,r;
    int w;
} tree[maxn*4];
inline void pushup(int root)
{
    tree[root].w = tree[lr].w + tree[rr].w;
}
void build(int root,int l,int r)
{
    tree[root].l = l;
    tree[root].r = r;
    if(l==r)
    {
        tree[root].w = 1;
        return ;
    }
    build(lr,l,mid);
    build(rr,mid+1,r);
    pushup(root);
}
inline void update(int root,int p,int type)///将结点p的 w 修改为type
{
    if(tree[root].l==tree[root].r)
    {
        tree[root].w=type;
        return ;
    }
    int l=tree[root].l;
    int r=tree[root].r;
    if(p<=mid)
    {
        update(lr,p,type);
    }
    else
    {
        update(rr,p,type);
    }
    pushup(root);
}
int query(int root,int l,int r)
{
    if(l<=tree[root].l&&tree[root].r<=r)
    {
        return tree[root].w;
    }
    int ans=0;
    if(l<=mid)ans += query(lr,l,r);
    if(r>mid)ans += query(rr,l,r);
    return ans;
}
int way(int u,int v)///记录u,v的最短路,且重链最大
{
    int ans=0;
    while(top[u]!= top[v])
    {
        int tp1=top[u];
        int tp2=top[v];
        if(dep[tp1]<dep[tp2])
        {
            swap(tp1,tp2);
            swap(u,v);
        }
        int tmp = query(1,dfn[tp1],dfn[u]);
        if(tmp<dfn[u]-dfn[v]+1)return -1;
        ///如果路径长度是小于重链的长度,说明 里面肯定有白边 不合法
        ans+=tmp;
        u=fa[tp1];
        tp1=top[u];
    }
    if(u==v)return ans;
    if(dep[u]>dep[v])
    {
        swap(u,v);
    }
    int tmp = query( 1,dfn[ son[u] ],dfn[v] );
    if(tmp<dfn[v]-dfn[u])return -1;
    ans += tmp;
    return ans;
}
struct E
{
    int x;
    int y;
}path[maxn];
int main()
{
    memset(head,-1,sizeof(head));
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d %d",&path[i].x,&path[i].y);
        add(path[i].x,path[i].y);
        add(path[i].y,path[i].x);
    }
    int root=1;
    dfs1(root,0,1);
    ///树的根,该结点的父亲,该结点目前的深度
    ///dfs2(root,root);

    for(int i=1;i<n;i++)
    {
        if(dfn[ path[i].x ]<dfn[ path[i].y ])
        {
            swap(path[i].x,path[i].y);
        }
    }
    /*build(1,1,n);
    int q;
    scanf("%d",&q);
    while(q--)
    {
        int  ask,u,v;
        scanf("%d %d %d",&ask,&u);
        if(ask==1)
        {
            update(1,dfn[ path[u].x ],1);
        }
        else if(ask==2)
        {
            update(1,dfn[ path[u].x ],0);
        }
        else
        {
            scanf("%d",&v);
            printf("%d\n",way(u,v));
        }
    }
printf("**");
}*/

dp[i][j]=dp[i][j]a[i][j].yd+a[i][j].ydxdp[i+1][j]+a[i][j].ydy*dp[i][j+1];
dp表示的是到达i,j点消耗的魔法值

求数学期望(概率dp)

#include<bits/stdc++.h>
using namespace std;
#define bug(x) cout<<#x<<"=="<<x<<endl;
const int maxn=1e5+10;
int a[maxn] = { 0 };
double dp[maxn] = { 0 };///记录概率
double now=1.0/6.0;
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        memset(a,-1,sizeof(a));
        for(int i=1; i<=m; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            a[u] = v;
        }
        memset(dp,0,sizeof(dp));
        for(int i=n-1;i>=0;i--)
        {
            if(~a[i])
            {
                dp[i]=dp[ a[i] ];
            }
            else
            {
                for(int j=1;j<=6;j++)
                {
                    if(i+j>=n)
                    {
                        dp[i]+=now*dp[n];
                    }
                    else
                    {
                        dp[i]+=now*dp[i+j];
                    }
                }
                dp[i]++;
            }
        }
        printf("%.4f\n",dp[0]);
    }
}

the moon

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
#define bug(x) cout<<#x<<"=="<<x<<endl;
double dp[1005]={0};
///i表示当前获奖的概率为 (0/1*i) %
int main()
{
    int T;
    scanf("%d",&T);
    int cas=0;
    while(T--)
    {
        double p;
        scanf("%lf",&p);
        memset(dp,0,sizeof(dp));
        p/=100;
        double hope = 1/p;
        dp[1000]=hope;///这是肯定会得奖的临界情况
        ///bug(hope);
        for(int i=999;i>=20;i--)
        {
            dp[i] += p*( (i/1000.0));
            ///第一种情况->直接得到
            dp[i] += p*(1.0-i/1000.0)*(1+dp[min(1000,i+20)]);
            ///第二种情况,比赛赢了但是没有抽到,转移到dp[i+20]的情况,
            ///而且注意+(1-i/1000)因为需要一盘转移到下一个情况
            dp[i] += (1-p)*(1+dp[min(1000,i+15)]);
            ///第三情况输了,转移到dp[i+15]的情况
        }
        cas++;
        printf("Case %d: %.10f\n",cas,dp[20]);
    }
    /*
    cin>>a;
    int len = a.length();
    int t;
    scanf("%d",&t);
    bug(t);
    a=' '+a;
    while(t--)
    {
        cin>>b;
        int blen=b.length();
        b=' '+b;
        ll ans=0;
        for(int i=1;i<=len;i++)
        {
            dp[i][0]=1;
            for(int j=1;j<=blen;j++)
            {
                dp[i][j]=dp[i-1][j];
                if(a[i]==b[j])
                {
                    dp[i][j]=max(dp[i][j],dp[i-1][j-1]);
                }
                if(a[i]=='?')
                {
                    dp[i][j]=max(dp[i-1][j-1],dp[i][j]);
                }
                if(a[i]=='?'&&j==1)
                {
                    dp[i][j]=max(1,dp[i][j]);
                }
                if(j==blen)
                {
                    ans += dp[i][j];
                }
            }
        }
        printf("%lld\n",ans);
    }
    */
}

求概率
1

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e3+10;
#define bug(x) cout<<#x<<"=="<<x<<endl;
double dp[1005][1005] = { 0 };
int main()
{
    int w,b;
    scanf("%d %d",&w,&b);
    for(int i=1;i<=1005;i++)dp[i][0]=1;
    for(int i=1;i<=w;i++)
    {
        for(int j=1;j<=b;j++)
        {
            dp[i][j] += (i*1.0/(i+j));
            double gl1=(j*1.0)/(i+j);
            double gl2=((j-1)*1.0)/(i+j-1);
            if(j>=3)
            {
                dp[i][j]+=gl1*gl2*(j-2)*1.0/(i+j-2)*dp[i][j-3];
            }
            if(i>=2)
            {
                dp[i][j]+=gl1*gl2*i*1.0/(i+j-2)*dp[i-1][j-2];
            }
        }
    }
    printf("%.9f\n",dp[w][b]);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值